Bug 445146 Move editor/ui from mozilla-central to comm-central, build changes r=KaiRo, move r/sr=Neil
authorMark Banner <bugzilla@standard8.plus.com>
Wed, 03 Sep 2008 14:35:06 +0100
changeset 250 ee719a0502491fc663bda942dcfc52c0825938d3
parent 249 78b3d6c649f71eff41fe3f486c6cc4f4b899fd35
child 251 7550895945478f458eb26e622fdb26fc450e2570
push id222
push userbugzilla@standard8.plus.com
push dateWed, 03 Sep 2008 13:37:12 +0000
treeherdercomm-central@ee719a050249 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersKaiRo, move
bugs445146
Bug 445146 Move editor/ui from mozilla-central to comm-central, build changes r=KaiRo, move r/sr=Neil
allmakefiles.sh
editor/ui/Makefile.in
editor/ui/composer.js
editor/ui/composer/content/ComposerCommands.js
editor/ui/composer/content/EditorAllTags.css
editor/ui/composer/content/EditorContent.css
editor/ui/composer/content/EditorContextMenu.js
editor/ui/composer/content/EditorContextMenuOverlay.xul
editor/ui/composer/content/EditorParagraphMarks.css
editor/ui/composer/content/StructBarContextMenu.js
editor/ui/composer/content/composerOverlay.xul
editor/ui/composer/content/editor.js
editor/ui/composer/content/editor.xul
editor/ui/composer/content/editorApplicationOverlay.js
editor/ui/composer/content/editorMailOverlay.xul
editor/ui/composer/content/editorNavigatorOverlay.xul
editor/ui/composer/content/editorOverlay.js
editor/ui/composer/content/editorOverlay.xul
editor/ui/composer/content/editorPrefsOverlay.xul
editor/ui/composer/content/editorSmileyOverlay.xul
editor/ui/composer/content/editorTasksOverlay.xul
editor/ui/composer/content/editorUtilities.js
editor/ui/composer/content/images/bringtofront-disabled.gif
editor/ui/composer/content/images/bringtofront.gif
editor/ui/composer/content/images/sendtoback-disabled.gif
editor/ui/composer/content/images/sendtoback.gif
editor/ui/composer/content/images/tag-a.gif
editor/ui/composer/content/images/tag-abr.gif
editor/ui/composer/content/images/tag-acr.gif
editor/ui/composer/content/images/tag-adr.gif
editor/ui/composer/content/images/tag-anchor.gif
editor/ui/composer/content/images/tag-app.gif
editor/ui/composer/content/images/tag-ara.gif
editor/ui/composer/content/images/tag-b.gif
editor/ui/composer/content/images/tag-bas.gif
editor/ui/composer/content/images/tag-bdo.gif
editor/ui/composer/content/images/tag-big.gif
editor/ui/composer/content/images/tag-blq.gif
editor/ui/composer/content/images/tag-body.gif
editor/ui/composer/content/images/tag-br.gif
editor/ui/composer/content/images/tag-bsf.gif
editor/ui/composer/content/images/tag-btn.gif
editor/ui/composer/content/images/tag-cit.gif
editor/ui/composer/content/images/tag-clg.gif
editor/ui/composer/content/images/tag-cod.gif
editor/ui/composer/content/images/tag-col.gif
editor/ui/composer/content/images/tag-cpt.gif
editor/ui/composer/content/images/tag-ctr.gif
editor/ui/composer/content/images/tag-dd.gif
editor/ui/composer/content/images/tag-del.gif
editor/ui/composer/content/images/tag-dfn.gif
editor/ui/composer/content/images/tag-dir.gif
editor/ui/composer/content/images/tag-div.gif
editor/ui/composer/content/images/tag-dl.gif
editor/ui/composer/content/images/tag-dt.gif
editor/ui/composer/content/images/tag-em.gif
editor/ui/composer/content/images/tag-fld.gif
editor/ui/composer/content/images/tag-fnt.gif
editor/ui/composer/content/images/tag-for.gif
editor/ui/composer/content/images/tag-frm.gif
editor/ui/composer/content/images/tag-fst.gif
editor/ui/composer/content/images/tag-h1.gif
editor/ui/composer/content/images/tag-h2.gif
editor/ui/composer/content/images/tag-h3.gif
editor/ui/composer/content/images/tag-h4.gif
editor/ui/composer/content/images/tag-h5.gif
editor/ui/composer/content/images/tag-h6.gif
editor/ui/composer/content/images/tag-hed.gif
editor/ui/composer/content/images/tag-hr.gif
editor/ui/composer/content/images/tag-html.gif
editor/ui/composer/content/images/tag-i.gif
editor/ui/composer/content/images/tag-ifr.gif
editor/ui/composer/content/images/tag-img.gif
editor/ui/composer/content/images/tag-inp.gif
editor/ui/composer/content/images/tag-ins.gif
editor/ui/composer/content/images/tag-isx.gif
editor/ui/composer/content/images/tag-kbd.gif
editor/ui/composer/content/images/tag-lbl.gif
editor/ui/composer/content/images/tag-lgn.gif
editor/ui/composer/content/images/tag-li.gif
editor/ui/composer/content/images/tag-lnk.gif
editor/ui/composer/content/images/tag-lst.gif
editor/ui/composer/content/images/tag-map.gif
editor/ui/composer/content/images/tag-men.gif
editor/ui/composer/content/images/tag-met.gif
editor/ui/composer/content/images/tag-nbr.gif
editor/ui/composer/content/images/tag-nfr.gif
editor/ui/composer/content/images/tag-nsc.gif
editor/ui/composer/content/images/tag-obj.gif
editor/ui/composer/content/images/tag-ol.gif
editor/ui/composer/content/images/tag-opg.gif
editor/ui/composer/content/images/tag-opt.gif
editor/ui/composer/content/images/tag-p.gif
editor/ui/composer/content/images/tag-pln.gif
editor/ui/composer/content/images/tag-pre.gif
editor/ui/composer/content/images/tag-prm.gif
editor/ui/composer/content/images/tag-q.gif
editor/ui/composer/content/images/tag-s.gif
editor/ui/composer/content/images/tag-scr.gif
editor/ui/composer/content/images/tag-slc.gif
editor/ui/composer/content/images/tag-sml.gif
editor/ui/composer/content/images/tag-smp.gif
editor/ui/composer/content/images/tag-spn.gif
editor/ui/composer/content/images/tag-stk.gif
editor/ui/composer/content/images/tag-stl.gif
editor/ui/composer/content/images/tag-stn.gif
editor/ui/composer/content/images/tag-sub.gif
editor/ui/composer/content/images/tag-sup.gif
editor/ui/composer/content/images/tag-tbd.gif
editor/ui/composer/content/images/tag-tbl.gif
editor/ui/composer/content/images/tag-td.gif
editor/ui/composer/content/images/tag-tft.gif
editor/ui/composer/content/images/tag-th.gif
editor/ui/composer/content/images/tag-thd.gif
editor/ui/composer/content/images/tag-tr.gif
editor/ui/composer/content/images/tag-tt.gif
editor/ui/composer/content/images/tag-ttl.gif
editor/ui/composer/content/images/tag-txt.gif
editor/ui/composer/content/images/tag-u.gif
editor/ui/composer/content/images/tag-ul.gif
editor/ui/composer/content/images/tag-userdefined.gif
editor/ui/composer/content/images/tag-var.gif
editor/ui/composer/content/images/tag-xmp.gif
editor/ui/composer/content/pref-composer.js
editor/ui/composer/content/pref-composer.xul
editor/ui/composer/content/pref-editing.xul
editor/ui/composer/content/pref-toolbars.xul
editor/ui/composer/content/publishprefs.js
editor/ui/dialogs/content/EdAEAttributes.js
editor/ui/dialogs/content/EdAECSSAttributes.js
editor/ui/dialogs/content/EdAEHTMLAttributes.js
editor/ui/dialogs/content/EdAEJSEAttributes.js
editor/ui/dialogs/content/EdAdvancedEdit.js
editor/ui/dialogs/content/EdAdvancedEdit.xul
editor/ui/dialogs/content/EdButtonProps.js
editor/ui/dialogs/content/EdButtonProps.xul
editor/ui/dialogs/content/EdColorPicker.js
editor/ui/dialogs/content/EdColorPicker.xul
editor/ui/dialogs/content/EdColorProps.js
editor/ui/dialogs/content/EdColorProps.xul
editor/ui/dialogs/content/EdConvertToTable.js
editor/ui/dialogs/content/EdConvertToTable.xul
editor/ui/dialogs/content/EdDialogCommon.js
editor/ui/dialogs/content/EdDialogOverlay.xul
editor/ui/dialogs/content/EdDialogTemplate.js
editor/ui/dialogs/content/EdDialogTemplate.xul
editor/ui/dialogs/content/EdDictionary.js
editor/ui/dialogs/content/EdDictionary.xul
editor/ui/dialogs/content/EdFieldSetProps.js
editor/ui/dialogs/content/EdFieldSetProps.xul
editor/ui/dialogs/content/EdFormProps.js
editor/ui/dialogs/content/EdFormProps.xul
editor/ui/dialogs/content/EdHLineProps.js
editor/ui/dialogs/content/EdHLineProps.xul
editor/ui/dialogs/content/EdImageMap.js
editor/ui/dialogs/content/EdImageMap.xul
editor/ui/dialogs/content/EdImageMapHotSpot.js
editor/ui/dialogs/content/EdImageMapHotSpot.xul
editor/ui/dialogs/content/EdImageMapPage.html
editor/ui/dialogs/content/EdImageMapShapes.js
editor/ui/dialogs/content/EdImageOverlay.js
editor/ui/dialogs/content/EdImageOverlay.xul
editor/ui/dialogs/content/EdImageProps.js
editor/ui/dialogs/content/EdImageProps.xul
editor/ui/dialogs/content/EdInputImage.js
editor/ui/dialogs/content/EdInputImage.xul
editor/ui/dialogs/content/EdInputProps.js
editor/ui/dialogs/content/EdInputProps.xul
editor/ui/dialogs/content/EdInsSrc.js
editor/ui/dialogs/content/EdInsSrc.xul
editor/ui/dialogs/content/EdInsertChars.js
editor/ui/dialogs/content/EdInsertChars.xul
editor/ui/dialogs/content/EdInsertTOC.js
editor/ui/dialogs/content/EdInsertTOC.xul
editor/ui/dialogs/content/EdInsertTable.js
editor/ui/dialogs/content/EdInsertTable.xul
editor/ui/dialogs/content/EdLabelProps.js
editor/ui/dialogs/content/EdLabelProps.xul
editor/ui/dialogs/content/EdLinkChecker.js
editor/ui/dialogs/content/EdLinkChecker.xul
editor/ui/dialogs/content/EdLinkProps.js
editor/ui/dialogs/content/EdLinkProps.xul
editor/ui/dialogs/content/EdListProps.js
editor/ui/dialogs/content/EdListProps.xul
editor/ui/dialogs/content/EdNamedAnchorProps.js
editor/ui/dialogs/content/EdNamedAnchorProps.xul
editor/ui/dialogs/content/EdPageProps.js
editor/ui/dialogs/content/EdPageProps.xul
editor/ui/dialogs/content/EdReplace.js
editor/ui/dialogs/content/EdReplace.xul
editor/ui/dialogs/content/EdSelectProps.js
editor/ui/dialogs/content/EdSelectProps.xul
editor/ui/dialogs/content/EdSnapToGrid.js
editor/ui/dialogs/content/EdSnapToGrid.xul
editor/ui/dialogs/content/EdSpellCheck.js
editor/ui/dialogs/content/EdSpellCheck.xul
editor/ui/dialogs/content/EdTableProps.js
editor/ui/dialogs/content/EdTableProps.xul
editor/ui/dialogs/content/EdTextAreaProps.js
editor/ui/dialogs/content/EdTextAreaProps.xul
editor/ui/dialogs/content/EditConflict.js
editor/ui/dialogs/content/EditConflict.xul
editor/ui/dialogs/content/EditorPublish.js
editor/ui/dialogs/content/EditorPublish.xul
editor/ui/dialogs/content/EditorPublishOverlay.xul
editor/ui/dialogs/content/EditorPublishProgress.js
editor/ui/dialogs/content/EditorPublishProgress.xul
editor/ui/dialogs/content/EditorPublishSettings.js
editor/ui/dialogs/content/EditorPublishSettings.xul
editor/ui/dialogs/content/EditorSaveAsCharset.js
editor/ui/dialogs/content/EditorSaveAsCharset.xul
editor/ui/jar.mn
editor/ui/locales/Makefile.in
editor/ui/locales/en-US/chrome/composer/editor.dtd
editor/ui/locales/en-US/chrome/composer/editor.properties
editor/ui/locales/en-US/chrome/composer/editorNavigatorOverlay.dtd
editor/ui/locales/en-US/chrome/composer/editorOverlay.dtd
editor/ui/locales/en-US/chrome/composer/editorPrefsOverlay.dtd
editor/ui/locales/en-US/chrome/composer/editorSmileyOverlay.dtd
editor/ui/locales/en-US/chrome/composer/pref-composer.dtd
editor/ui/locales/en-US/chrome/composer/pref-editing.dtd
editor/ui/locales/en-US/chrome/composer/pref-toolbars.dtd
editor/ui/locales/en-US/chrome/dialogs/EdAdvancedEdit.dtd
editor/ui/locales/en-US/chrome/dialogs/EdColorPicker.dtd
editor/ui/locales/en-US/chrome/dialogs/EdConvertToTable.dtd
editor/ui/locales/en-US/chrome/dialogs/EdDialogOverlay.dtd
editor/ui/locales/en-US/chrome/dialogs/EdLinkChecker.dtd
editor/ui/locales/en-US/chrome/dialogs/EdNamedAnchorProperties.dtd
editor/ui/locales/en-US/chrome/dialogs/EditConflict.dtd
editor/ui/locales/en-US/chrome/dialogs/EditorButtonProperties.dtd
editor/ui/locales/en-US/chrome/dialogs/EditorColorProperties.dtd
editor/ui/locales/en-US/chrome/dialogs/EditorFieldSetProperties.dtd
editor/ui/locales/en-US/chrome/dialogs/EditorFormProperties.dtd
editor/ui/locales/en-US/chrome/dialogs/EditorHLineProperties.dtd
editor/ui/locales/en-US/chrome/dialogs/EditorImageMap.dtd
editor/ui/locales/en-US/chrome/dialogs/EditorImageMapHotSpot.dtd
editor/ui/locales/en-US/chrome/dialogs/EditorImageProperties.dtd
editor/ui/locales/en-US/chrome/dialogs/EditorInputProperties.dtd
editor/ui/locales/en-US/chrome/dialogs/EditorInsertChars.dtd
editor/ui/locales/en-US/chrome/dialogs/EditorInsertSource.dtd
editor/ui/locales/en-US/chrome/dialogs/EditorInsertTOC.dtd
editor/ui/locales/en-US/chrome/dialogs/EditorInsertTable.dtd
editor/ui/locales/en-US/chrome/dialogs/EditorLabelProperties.dtd
editor/ui/locales/en-US/chrome/dialogs/EditorLinkProperties.dtd
editor/ui/locales/en-US/chrome/dialogs/EditorListProperties.dtd
editor/ui/locales/en-US/chrome/dialogs/EditorPageProperties.dtd
editor/ui/locales/en-US/chrome/dialogs/EditorPersonalDictionary.dtd
editor/ui/locales/en-US/chrome/dialogs/EditorPublish.dtd
editor/ui/locales/en-US/chrome/dialogs/EditorPublishProgress.dtd
editor/ui/locales/en-US/chrome/dialogs/EditorReplace.dtd
editor/ui/locales/en-US/chrome/dialogs/EditorSaveAsCharset.dtd
editor/ui/locales/en-US/chrome/dialogs/EditorSelectProperties.dtd
editor/ui/locales/en-US/chrome/dialogs/EditorSnapToGrid.dtd
editor/ui/locales/en-US/chrome/dialogs/EditorSpellCheck.dtd
editor/ui/locales/en-US/chrome/dialogs/EditorTableProperties.dtd
editor/ui/locales/en-US/chrome/dialogs/EditorTextAreaProperties.dtd
editor/ui/locales/en-US/chrome/region/region.properties
editor/ui/locales/jar.mn
editor/ui/makefiles.sh
editor/ui/nsComposerCmdLineHandler.js
mail/build.mk
mail/locales/Makefile.in
suite/build.mk
suite/locales/Makefile.in
--- a/allmakefiles.sh
+++ b/allmakefiles.sh
@@ -59,16 +59,20 @@ add_makefiles "
 Makefile
 config/autoconf.mk
 "
 
 if [ "$MOZ_LDAP_XPCOM" ]; then
   . "${srcdir}/directory/makefiles.sh"
 fi
 
+if [ "$MOZ_COMPOSER" ]; then
+  . "${srcdir}/editor/ui/makefiles.sh"
+fi
+
 if [ "$MOZ_MAIL_NEWS" ]; then
   . "${srcdir}/mailnews/makefiles.sh"
 fi
 
 if [ "$MOZ_CALENDAR" ]; then
   . "${srcdir}/calendar/shared_makefiles.sh"
   . "${srcdir}/calendar/lightning/makefiles.sh"
 fi
new file mode 100644
--- /dev/null
+++ b/editor/ui/Makefile.in
@@ -0,0 +1,54 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications.
+# Portions created by the Initial Developer are Copyright (C) 2001
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#  Brian Ryner <bryner@brianryner.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH		= ../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+DIRS           = \
+               locales \
+               $(NULL)
+
+ifndef MOZ_STANDALONE_COMPOSER
+PREF_JS_EXPORTS = $(srcdir)/composer.js
+EXTRA_COMPONENTS = nsComposerCmdLineHandler.js
+endif
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/editor/ui/composer.js
@@ -0,0 +1,138 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Benjamin Smedberg <bsmedberg@covad.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**
+ * Default preferences for seamonkey composer. This file
+ * was copied from mozilla/modules/libpref/src/init/editor.js
+ *
+ * If you're looking for the default prefs of standalone
+ * composer, see mozilla/composer/app/profile/all.js
+ */
+
+pref("editor.author",                       "");
+
+pref("editor.text_color",                   "#000000");
+pref("editor.link_color",                   "#0000FF");
+pref("editor.active_link_color",            "#000088");
+pref("editor.followed_link_color",          "#FF0000");
+pref("editor.background_color",             "#FFFFFF");
+pref("editor.use_background_image",         false);
+pref("editor.default_background_image",     "");
+pref("editor.use_custom_default_colors", 1);
+
+pref("editor.hrule.height",                 2);
+pref("editor.hrule.width",                  100);
+pref("editor.hrule.width_percent",          true);
+pref("editor.hrule.shading",                true);
+pref("editor.hrule.align",                  1); // center
+
+pref("editor.table.maintain_structure", true);
+
+pref("editor.prettyprint", true);
+
+pref("editor.throbber.url","chrome://editor-region/locale/region.properties");
+
+pref("editor.toolbars.showbutton.new", true);
+pref("editor.toolbars.showbutton.open", true);
+pref("editor.toolbars.showbutton.save", true);
+pref("editor.toolbars.showbutton.publish", true);
+pref("editor.toolbars.showbutton.preview", true);
+pref("editor.toolbars.showbutton.cut", false);
+pref("editor.toolbars.showbutton.copy", false);
+pref("editor.toolbars.showbutton.paste", false);
+pref("editor.toolbars.showbutton.print", true);
+pref("editor.toolbars.showbutton.find", false);
+pref("editor.toolbars.showbutton.image", true);
+pref("editor.toolbars.showbutton.hline", false);
+pref("editor.toolbars.showbutton.table", true);
+pref("editor.toolbars.showbutton.link", true);
+pref("editor.toolbars.showbutton.namedAnchor", false);
+
+pref("editor.toolbars.showbutton.bold", true);
+pref("editor.toolbars.showbutton.italic", true);
+pref("editor.toolbars.showbutton.underline", true);
+pref("editor.toolbars.showbutton.DecreaseFontSize", true);
+pref("editor.toolbars.showbutton.IncreaseFontSize", true);
+pref("editor.toolbars.showbutton.ul", true);
+pref("editor.toolbars.showbutton.ol", true);
+pref("editor.toolbars.showbutton.outdent", true);
+pref("editor.toolbars.showbutton.indent", true);
+
+pref("editor.toolbars.showbutton.absolutePosition", true);
+pref("editor.toolbars.showbutton.decreaseZIndex", true);
+pref("editor.toolbars.showbutton.increaseZIndex", true);
+
+pref("editor.history.url_maximum", 10);
+
+pref("editor.publish.",                      "");
+pref("editor.lastFileLocation.image",        "");
+pref("editor.lastFileLocation.html",         "");
+pref("editor.save_associated_files",         true);
+pref("editor.always_show_publish_dialog",    false);
+
+/*
+ * What are the entities that you want Mozilla to save using mnemonic
+ * names rather than numeric codes? E.g. If set, we'll output &nbsp;
+ * otherwise, we may output 0xa0 depending on the charset.
+ *
+ * "none"   : don't use any entity names; only use numeric codes.
+ * "basic"  : use entity names just for &nbsp; &amp; &lt; &gt; &quot; for 
+ *            interoperability/exchange with products that don't support more
+ *            than that.
+ * "latin1" : use entity names for 8bit accented letters and other special
+ *            symbols between 128 and 255.
+ * "html"   : use entity names for 8bit accented letters, greek letters, and
+ *            other special markup symbols as defined in HTML4.
+ */
+//pref("editor.encode_entity",                 "html");
+
+#ifndef XP_MACOSX
+#ifdef XP_UNIX
+pref("editor.disable_spell_checker", false);
+pref("editor.dont_lock_spell_files", true);
+#endif
+#endif
+
+pref("editor.CR_creates_new_p",      false);
+
+// Pasting images from the clipboard, order of encoding preference: 
+// JPEG-PNG-GIF=0, PNG-JPEG-GIF=1, GIF-JPEG-PNG=2
+pref("clipboard.paste_image_type", 1);
+#ifdef XP_WIN
+pref("clipboard.paste_image_quality", 92); // for JPEG on Windows only
+#endif
new file mode 100644
--- /dev/null
+++ b/editor/ui/composer/content/ComposerCommands.js
@@ -0,0 +1,3956 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Simon Fraser (sfraser@netscape.com)
+ *   Ryan Cassin (rcassin@supernova.org)
+ *   Kathleen Brade (brade@netscape.com)
+ *   Daniel Glazman (glazman@netscape.com)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* Implementations of nsIControllerCommand for composer commands */
+
+var gComposerJSCommandControllerID = 0;
+
+
+//-----------------------------------------------------------------------------------
+function SetupHTMLEditorCommands()
+{
+  var commandTable = GetComposerCommandTable();
+  if (!commandTable)
+    return;
+  
+  // Include everthing a text editor does
+  SetupTextEditorCommands();
+
+  //dump("Registering HTML editor commands\n");
+
+  commandTable.registerCommand("cmd_renderedHTMLEnabler", nsDummyHTMLCommand);
+
+  commandTable.registerCommand("cmd_grid",  nsGridCommand);
+
+  commandTable.registerCommand("cmd_listProperties",  nsListPropertiesCommand);
+  commandTable.registerCommand("cmd_pageProperties",  nsPagePropertiesCommand);
+  commandTable.registerCommand("cmd_colorProperties", nsColorPropertiesCommand);
+  commandTable.registerCommand("cmd_advancedProperties", nsAdvancedPropertiesCommand);
+  commandTable.registerCommand("cmd_objectProperties",   nsObjectPropertiesCommand);
+  commandTable.registerCommand("cmd_removeNamedAnchors", nsRemoveNamedAnchorsCommand);
+  commandTable.registerCommand("cmd_editLink",        nsEditLinkCommand);
+  
+  commandTable.registerCommand("cmd_form",          nsFormCommand);
+  commandTable.registerCommand("cmd_inputtag",      nsInputTagCommand);
+  commandTable.registerCommand("cmd_inputimage",    nsInputImageCommand);
+  commandTable.registerCommand("cmd_textarea",      nsTextAreaCommand);
+  commandTable.registerCommand("cmd_select",        nsSelectCommand);
+  commandTable.registerCommand("cmd_button",        nsButtonCommand);
+  commandTable.registerCommand("cmd_label",         nsLabelCommand);
+  commandTable.registerCommand("cmd_fieldset",      nsFieldSetCommand);
+  commandTable.registerCommand("cmd_isindex",       nsIsIndexCommand);
+  commandTable.registerCommand("cmd_image",         nsImageCommand);
+  commandTable.registerCommand("cmd_hline",         nsHLineCommand);
+  commandTable.registerCommand("cmd_link",          nsLinkCommand);
+  commandTable.registerCommand("cmd_anchor",        nsAnchorCommand);
+  commandTable.registerCommand("cmd_insertHTMLWithDialog", nsInsertHTMLWithDialogCommand);
+  commandTable.registerCommand("cmd_insertBreak",   nsInsertBreakCommand);
+  commandTable.registerCommand("cmd_insertBreakAll",nsInsertBreakAllCommand);
+
+  commandTable.registerCommand("cmd_table",              nsInsertOrEditTableCommand);
+  commandTable.registerCommand("cmd_editTable",          nsEditTableCommand);
+  commandTable.registerCommand("cmd_SelectTable",        nsSelectTableCommand);
+  commandTable.registerCommand("cmd_SelectRow",          nsSelectTableRowCommand);
+  commandTable.registerCommand("cmd_SelectColumn",       nsSelectTableColumnCommand);
+  commandTable.registerCommand("cmd_SelectCell",         nsSelectTableCellCommand);
+  commandTable.registerCommand("cmd_SelectAllCells",     nsSelectAllTableCellsCommand);
+  commandTable.registerCommand("cmd_InsertTable",        nsInsertTableCommand);
+  commandTable.registerCommand("cmd_InsertRowAbove",     nsInsertTableRowAboveCommand);
+  commandTable.registerCommand("cmd_InsertRowBelow",     nsInsertTableRowBelowCommand);
+  commandTable.registerCommand("cmd_InsertColumnBefore", nsInsertTableColumnBeforeCommand);
+  commandTable.registerCommand("cmd_InsertColumnAfter",  nsInsertTableColumnAfterCommand);
+  commandTable.registerCommand("cmd_InsertCellBefore",   nsInsertTableCellBeforeCommand);
+  commandTable.registerCommand("cmd_InsertCellAfter",    nsInsertTableCellAfterCommand);
+  commandTable.registerCommand("cmd_DeleteTable",        nsDeleteTableCommand);
+  commandTable.registerCommand("cmd_DeleteRow",          nsDeleteTableRowCommand);
+  commandTable.registerCommand("cmd_DeleteColumn",       nsDeleteTableColumnCommand);
+  commandTable.registerCommand("cmd_DeleteCell",         nsDeleteTableCellCommand);
+  commandTable.registerCommand("cmd_DeleteCellContents", nsDeleteTableCellContentsCommand);
+  commandTable.registerCommand("cmd_JoinTableCells",     nsJoinTableCellsCommand);
+  commandTable.registerCommand("cmd_SplitTableCell",     nsSplitTableCellCommand);
+  commandTable.registerCommand("cmd_TableOrCellColor",   nsTableOrCellColorCommand);
+  commandTable.registerCommand("cmd_NormalizeTable",     nsNormalizeTableCommand);
+  commandTable.registerCommand("cmd_smiley",             nsSetSmiley);
+  commandTable.registerCommand("cmd_ConvertToTable",     nsConvertToTable);
+}
+
+function SetupTextEditorCommands()
+{
+  var commandTable = GetComposerCommandTable();
+  if (!commandTable)
+    return;
+  
+  //dump("Registering plain text editor commands\n");
+  
+  commandTable.registerCommand("cmd_find",       nsFindCommand);
+  commandTable.registerCommand("cmd_findNext",   nsFindAgainCommand);
+  commandTable.registerCommand("cmd_findPrev",   nsFindAgainCommand);
+  commandTable.registerCommand("cmd_rewrap",     nsRewrapCommand);
+  commandTable.registerCommand("cmd_spelling",   nsSpellingCommand);
+  commandTable.registerCommand("cmd_validate",   nsValidateCommand);
+  commandTable.registerCommand("cmd_checkLinks", nsCheckLinksCommand);
+  commandTable.registerCommand("cmd_insertChars", nsInsertCharsCommand);
+}
+
+function SetupComposerWindowCommands()
+{
+  // Don't need to do this if already done
+  if (gComposerWindowControllerID)
+    return;
+
+  // Create a command controller and register commands
+  //   specific to Web Composer window (file-related commands, HTML Source...)
+  //   We can't use the composer controller created on the content window else
+  //     we can't process commands when in HTMLSource editor
+  // IMPORTANT: For each of these commands, the doCommand method 
+  //            must first call FinishHTMLSource() 
+  //            to go from HTML Source mode to any other edit mode
+
+  var windowControllers = window.controllers;
+
+  if (!windowControllers) return;
+
+  var commandTable;
+  var composerController;
+  var editorController;
+  try {
+    composerController = Components.classes["@mozilla.org/embedcomp/base-command-controller;1"].createInstance();
+
+    editorController = composerController.QueryInterface(Components.interfaces.nsIControllerContext);
+    editorController.init(null); // init it without passing in a command table
+
+    // Get the nsIControllerCommandTable interface we need to register commands
+    var interfaceRequestor = composerController.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
+    commandTable = interfaceRequestor.getInterface(Components.interfaces.nsIControllerCommandTable);
+  }
+  catch (e)
+  {
+    dump("Failed to create composerController\n");
+    return;
+  }
+
+
+  if (!commandTable)
+  {
+    dump("Failed to get interface for nsIControllerCommandManager\n");
+    return;
+  }
+
+  // File-related commands
+  commandTable.registerCommand("cmd_open",           nsOpenCommand);
+  commandTable.registerCommand("cmd_save",           nsSaveCommand);
+  commandTable.registerCommand("cmd_saveAs",         nsSaveAsCommand);
+  commandTable.registerCommand("cmd_exportToText",   nsExportToTextCommand);
+  commandTable.registerCommand("cmd_saveAndChangeEncoding",  nsSaveAndChangeEncodingCommand);
+  commandTable.registerCommand("cmd_publish",        nsPublishCommand);
+  commandTable.registerCommand("cmd_publishAs",      nsPublishAsCommand);
+  commandTable.registerCommand("cmd_publishSettings",nsPublishSettingsCommand);
+  commandTable.registerCommand("cmd_revert",         nsRevertCommand);
+  commandTable.registerCommand("cmd_openRemote",     nsOpenRemoteCommand);
+  commandTable.registerCommand("cmd_preview",        nsPreviewCommand);
+  commandTable.registerCommand("cmd_editSendPage",   nsSendPageCommand);
+  commandTable.registerCommand("cmd_print",          nsPrintCommand);
+  commandTable.registerCommand("cmd_printSetup",     nsPrintSetupCommand);
+  commandTable.registerCommand("cmd_quit",           nsQuitCommand);
+  commandTable.registerCommand("cmd_close",          nsCloseCommand);
+  commandTable.registerCommand("cmd_preferences",    nsPreferencesCommand);
+
+  // Edit Mode commands
+  if (GetCurrentEditorType() == "html")
+  {
+    commandTable.registerCommand("cmd_NormalMode",         nsNormalModeCommand);
+    commandTable.registerCommand("cmd_AllTagsMode",        nsAllTagsModeCommand);
+    commandTable.registerCommand("cmd_HTMLSourceMode",     nsHTMLSourceModeCommand);
+    commandTable.registerCommand("cmd_PreviewMode",        nsPreviewModeCommand);
+    commandTable.registerCommand("cmd_FinishHTMLSource",   nsFinishHTMLSource);
+    commandTable.registerCommand("cmd_CancelHTMLSource",   nsCancelHTMLSource);
+    commandTable.registerCommand("cmd_updateStructToolbar", nsUpdateStructToolbarCommand);
+  }
+
+  windowControllers.insertControllerAt(0, editorController);
+
+  // Store the controller ID so we can be sure to get the right one later
+  gComposerWindowControllerID = windowControllers.getControllerId(editorController);
+}
+
+//-----------------------------------------------------------------------------------
+function GetComposerCommandTable()
+{
+  var controller;
+  if (gComposerJSCommandControllerID)
+  {
+    try { 
+      controller = window.content.controllers.getControllerById(gComposerJSCommandControllerID);
+    } catch (e) {}
+  }
+  if (!controller)
+  {
+    //create it
+    controller = Components.classes["@mozilla.org/embedcomp/base-command-controller;1"].createInstance();
+
+    var editorController = controller.QueryInterface(Components.interfaces.nsIControllerContext);
+    editorController.init(null);
+    editorController.setCommandContext(GetCurrentEditorElement());
+    window.content.controllers.insertControllerAt(0, controller);
+  
+    // Store the controller ID so we can be sure to get the right one later
+    gComposerJSCommandControllerID = window.content.controllers.getControllerId(controller);
+  }
+
+  if (controller)
+  {
+    var interfaceRequestor = controller.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
+    return interfaceRequestor.getInterface(Components.interfaces.nsIControllerCommandTable);
+  }
+  return null;
+}
+
+//-----------------------------------------------------------------------------------
+function goUpdateCommandState(command)
+{
+  try
+  {
+    var controller = top.document.commandDispatcher.getControllerForCommand(command);
+    if (!(controller instanceof Components.interfaces.nsICommandController))
+      return;
+
+    var params = newCommandParams();
+    if (!params) return;
+
+    controller.getCommandStateWithParams(command, params);
+
+    switch (command)
+    {
+      case "cmd_bold":
+      case "cmd_italic":
+      case "cmd_underline":
+      case "cmd_var":
+      case "cmd_samp":
+      case "cmd_code":
+      case "cmd_acronym":
+      case "cmd_abbr":
+      case "cmd_cite":
+      case "cmd_strong":
+      case "cmd_em":
+      case "cmd_superscript":
+      case "cmd_subscript":
+      case "cmd_strikethrough":
+      case "cmd_tt":
+      case "cmd_nobreak":
+      case "cmd_ul":
+      case "cmd_ol":
+        pokeStyleUI(command, params.getBooleanValue("state_all"));
+        break;
+
+      case "cmd_paragraphState":
+      case "cmd_align":
+      case "cmd_highlight":
+      case "cmd_backgroundColor":
+      case "cmd_fontColor":
+      case "cmd_fontFace":
+      case "cmd_fontSize":
+      case "cmd_absPos":
+        pokeMultiStateUI(command, params);
+        break;
+
+      case "cmd_decreaseZIndex":
+      case "cmd_increaseZIndex":
+      case "cmd_indent":
+      case "cmd_outdent":
+      case "cmd_increaseFont":
+      case "cmd_decreaseFont":
+      case "cmd_removeStyles":
+      case "cmd_smiley":
+        break;
+
+      default: dump("no update for command: " +command+"\n");
+    }
+  }
+  catch (e) { dump("An error occurred updating the "+command+" command: \n"+e+"\n"); }
+}
+
+function goUpdateComposerMenuItems(commandset)
+{
+  //dump("Updating commands for " + commandset.id + "\n");
+
+  for (var i = 0; i < commandset.childNodes.length; i++)
+  {
+    var commandNode = commandset.childNodes[i];
+    var commandID = commandNode.id;
+    if (commandID)
+    {
+      goUpdateCommand(commandID);  // enable or disable
+      if (commandNode.hasAttribute("state"))
+        goUpdateCommandState(commandID);
+    }
+  }
+}
+
+//-----------------------------------------------------------------------------------
+function goDoCommandParams(command, params)
+{
+  try
+  {
+    var controller = top.document.commandDispatcher.getControllerForCommand(command);
+    if (controller && controller.isCommandEnabled(command))
+    {
+      if (controller instanceof Components.interfaces.nsICommandController)
+      {
+        controller.doCommandWithParams(command, params);
+
+        // the following two lines should be removed when we implement observers
+        if (params)
+          controller.getCommandStateWithParams(command, params);
+      }
+      else
+      {
+        controller.doCommand(command);
+      }
+      ResetStructToolbar();
+    }
+  }
+  catch (e)
+  {
+    dump("An error occurred executing the "+command+" command\n");
+  }
+}
+
+function pokeStyleUI(uiID, aDesiredState)
+{
+ try {
+  var commandNode = top.document.getElementById(uiID);
+  if (!commandNode)
+    return;
+
+  var uiState = ("true" == commandNode.getAttribute("state"));
+  if (aDesiredState != uiState)
+  {
+    var newState;
+    if (aDesiredState)
+      newState = "true";
+    else
+      newState = "false";
+    commandNode.setAttribute("state", newState);
+  }
+ } catch(e) { dump("poking UI for "+uiID+" failed: "+e+"\n"); }
+}
+
+function doStyleUICommand(cmdStr)
+{
+  try
+  {
+    var cmdParams = newCommandParams();
+    goDoCommandParams(cmdStr, cmdParams);
+    if (cmdParams)
+      pokeStyleUI(cmdStr, cmdParams.getBooleanValue("state_all"));
+
+    ResetStructToolbar();
+  } catch(e) {}
+}
+
+function pokeMultiStateUI(uiID, cmdParams)
+{
+  try
+  {
+    var commandNode = document.getElementById(uiID);
+    if (!commandNode)
+      return;
+
+    var isMixed = cmdParams.getBooleanValue("state_mixed");
+    var desiredAttrib;
+    if (isMixed)
+      desiredAttrib = "mixed";
+    else {
+      var valuetype = cmdParams.getValueType("state_attribute");
+      if (valuetype == Components.interfaces.nsICommandParams.eStringType) {
+        desiredAttrib = cmdParams.getCStringValue("state_attribute");      
+      } else {
+        desiredAttrib = cmdParams.getStringValue("state_attribute");      
+      }
+
+    }
+
+    var uiState = commandNode.getAttribute("state");
+    if (desiredAttrib != uiState)
+    {
+      commandNode.setAttribute("state", desiredAttrib);
+    }
+  } catch(e) {}
+}
+
+function doStatefulCommand(commandID, newState)
+{
+  var commandNode = document.getElementById(commandID);
+  if (commandNode)
+      commandNode.setAttribute("state", newState);
+  gContentWindow.focus();   // needed for command dispatch to work
+
+  try
+  {
+    var cmdParams = newCommandParams();
+    if (!cmdParams) return;
+
+    cmdParams.setStringValue("state_attribute", newState);
+    goDoCommandParams(commandID, cmdParams);
+
+    pokeMultiStateUI(commandID, cmdParams);
+
+    ResetStructToolbar();
+  } catch(e) { dump("error thrown in doStatefulCommand: "+e+"\n"); }
+}
+
+//-----------------------------------------------------------------------------------
+function PrintObject(obj)
+{
+  dump("-----" + obj + "------\n");
+  var names = "";
+  for (var i in obj)
+  {
+    if (i == "value")
+      names += i + ": " + obj.value + "\n";
+    else if (i == "id")
+      names += i + ": " + obj.id + "\n";
+    else
+      names += i + "\n";
+  }
+  
+  dump(names + "-----------\n");
+}
+
+//-----------------------------------------------------------------------------------
+function PrintNodeID(id)
+{
+  PrintObject(document.getElementById(id));
+}
+
+//-----------------------------------------------------------------------------------
+var nsDummyHTMLCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable() && IsEditingRenderedHTML());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    // do nothing
+    dump("Hey, who's calling the dummy command?\n");
+  }
+
+};
+
+//-----------------------------------------------------------------------------------
+var nsOpenCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return true;    // we can always do this
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
+    fp.init(window, GetString("OpenHTMLFile"), nsIFilePicker.modeOpen);
+
+    SetFilePickerDirectory(fp, "html");
+
+    // When loading into Composer, direct user to prefer HTML files and text files,
+    //   so we call separately to control the order of the filter list
+    fp.appendFilters(nsIFilePicker.filterHTML);
+    fp.appendFilters(nsIFilePicker.filterText);
+    fp.appendFilters(nsIFilePicker.filterAll);
+
+    /* doesn't handle *.shtml files */
+    try {
+      fp.show();
+      /* need to handle cancel (uncaught exception at present) */
+    }
+    catch (ex) {
+      dump("filePicker.chooseInputFile threw an exception\n");
+    }
+  
+    /* This checks for already open window and activates it... 
+     * note that we have to test the native path length
+     *  since file.URL will be "file:///" if no filename picked (Cancel button used)
+     */
+    if (fp.file && fp.file.path.length > 0) {
+      SaveFilePickerDirectory(fp, "html");
+      editPage(fp.fileURL.spec, window, false);
+    }
+  }
+};
+
+// STRUCTURE TOOLBAR
+//
+var nsUpdateStructToolbarCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    UpdateStructToolbar();
+    return true;
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+  doCommand: function(aCommand)  {}
+}
+
+// ******* File output commands and utilities ******** //
+//-----------------------------------------------------------------------------------
+var nsSaveCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    // Always allow saving when editing a remote document,
+    //  otherwise the document modified state would prevent that
+    //  when you first open a remote file.
+    try {
+      var docUrl = GetDocumentUrl();
+      return IsDocumentEditable() &&
+        (IsDocumentModified() || IsHTMLSourceChanged() ||
+         IsUrlAboutBlank(docUrl) || GetScheme(docUrl) != "file");
+    } catch (e) {return false;}
+  },
+  
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    var result = false;
+    var editor = GetCurrentEditor();
+    if (editor)
+    {
+      FinishHTMLSource();
+      result = SaveDocument(IsUrlAboutBlank(GetDocumentUrl()), false, editor.contentsMIMEType);
+      window.content.focus();
+    }
+    return result;
+  }
+}
+
+var nsSaveAsCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    var editor = GetCurrentEditor();
+    if (editor)
+    {
+      FinishHTMLSource();
+      var result = SaveDocument(true, false, editor.contentsMIMEType);
+      window.content.focus();
+      return result;
+    }
+    return false;
+  }
+}
+
+var nsExportToTextCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    if (GetCurrentEditor())
+    {
+      FinishHTMLSource();
+      var result = SaveDocument(true, true, "text/plain");
+      window.content.focus();
+      return result;
+    }
+    return false;
+  }
+}
+
+var nsSaveAndChangeEncodingCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {    
+    FinishHTMLSource();
+    window.ok = false;
+    window.exportToText = false;
+    var oldTitle = GetDocumentTitle();
+    window.openDialog("chrome://editor/content/EditorSaveAsCharset.xul","_blank", "chrome,close,titlebar,modal,resizable=yes");
+
+    if (GetDocumentTitle() != oldTitle)
+      UpdateWindowTitle();
+
+    if (window.ok)
+    {
+      if (window.exportToText)
+      {
+        window.ok = SaveDocument(true, true, "text/plain");
+      }
+      else
+      {
+        var editor = GetCurrentEditor();
+        window.ok = SaveDocument(true, false, editor ? editor.contentsMIMEType : null);
+      }
+    }
+
+    window.content.focus();
+    return window.ok;
+  }
+};
+
+var nsPublishCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    if (IsDocumentEditable())
+    {
+      // Always allow publishing when editing a local document,
+      //  otherwise the document modified state would prevent that
+      //  when you first open any local file.
+      try {
+        var docUrl = GetDocumentUrl();
+        return IsDocumentModified() || IsHTMLSourceChanged()
+               || IsUrlAboutBlank(docUrl) || GetScheme(docUrl) == "file";
+      } catch (e) {return false;}
+    }
+    return false;
+  },
+  
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    if (GetCurrentEditor())
+    {
+      var docUrl = GetDocumentUrl();
+      var filename = GetFilename(docUrl);
+      var publishData;
+      var showPublishDialog = false;
+
+      // First check pref to always show publish dialog
+      try {
+        var prefs = GetPrefs();
+        if (prefs)
+          showPublishDialog = prefs.getBoolPref("editor.always_show_publish_dialog");
+      } catch(e) {}
+
+      if (!showPublishDialog && filename)
+      {
+        // Try to get publish data from the document url
+        publishData = CreatePublishDataFromUrl(docUrl);
+
+        // If none, use default publishing site? Need a pref for this
+        //if (!publishData)
+        //  publishData = GetPublishDataFromSiteName(GetDefaultPublishSiteName(), filename);
+      }
+
+      if (showPublishDialog || !publishData)
+      {
+        // Show the publish dialog
+        publishData = {};
+        window.ok = false;
+        var oldTitle = GetDocumentTitle();
+        window.openDialog("chrome://editor/content/EditorPublish.xul","_blank", 
+                          "chrome,close,titlebar,modal", "", "", publishData);
+        if (GetDocumentTitle() != oldTitle)
+          UpdateWindowTitle();
+
+        window.content.focus();
+        if (!window.ok)
+          return false;
+      }
+      if (publishData)
+      {
+        FinishHTMLSource();
+        return Publish(publishData);
+      }
+    }
+    return false;
+  }
+}
+
+var nsPublishAsCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable());
+  },
+  
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    if (GetCurrentEditor())
+    {
+      FinishHTMLSource();
+
+      window.ok = false;
+      var publishData = {};
+      var oldTitle = GetDocumentTitle();
+      window.openDialog("chrome://editor/content/EditorPublish.xul","_blank", 
+                        "chrome,close,titlebar,modal", "", "", publishData);
+      if (GetDocumentTitle() != oldTitle)
+        UpdateWindowTitle();
+
+      window.content.focus();
+      if (window.ok)
+        return Publish(publishData);
+    }
+    return false;
+  }
+}
+
+// ------- output utilites   ----- //
+
+// returns a fileExtension string
+function GetExtensionBasedOnMimeType(aMIMEType)
+{
+  try {
+    var mimeService = null;
+    mimeService = Components.classes["@mozilla.org/mime;1"].getService();
+    mimeService = mimeService.QueryInterface(Components.interfaces.nsIMIMEService);
+
+    var fileExtension = mimeService.getPrimaryExtension(aMIMEType, null);
+
+    // the MIME service likes to give back ".htm" for text/html files,
+    // so do a special-case fix here.
+    if (fileExtension == "htm")
+      fileExtension = "html";
+
+    return fileExtension;
+  }
+  catch (e) {}
+  return "";
+}
+
+function GetSuggestedFileName(aDocumentURLString, aMIMEType)
+{
+  var extension = GetExtensionBasedOnMimeType(aMIMEType);
+  if (extension)
+    extension = "." + extension;
+
+  // check for existing file name we can use
+  if (aDocumentURLString.length >= 0 && !IsUrlAboutBlank(aDocumentURLString))
+  {
+    var docURI = null;
+    try {
+
+      var ioService = GetIOService();
+      docURI = ioService.newURI(aDocumentURLString, GetCurrentEditor().documentCharacterSet, null);
+      docURI = docURI.QueryInterface(Components.interfaces.nsIURL);
+
+      // grab the file name
+      var url = docURI.fileBaseName;
+      if (url)
+        return url+extension;
+    } catch(e) {}
+  } 
+
+  // check if there is a title we can use
+  var title = GetDocumentTitle();
+  // generate a valid filename, if we can't just go with "untitled"
+  return GenerateValidFilename(title, extension) || GetString("untitled") + extension;
+}
+
+// returns file picker result
+function PromptForSaveLocation(aDoSaveAsText, aEditorType, aMIMEType, aDocumentURLString)
+{
+  var dialogResult = {};
+  dialogResult.filepickerClick = nsIFilePicker.returnCancel;
+  dialogResult.resultingURI = "";
+  dialogResult.resultingLocalFile = null;
+
+  var fp = null;
+  try {
+    fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
+  } catch (e) {}
+  if (!fp) return dialogResult;
+
+  // determine prompt string based on type of saving we'll do
+  var promptString;
+  if (aDoSaveAsText || aEditorType == "text")
+    promptString = GetString("ExportToText");
+  else
+    promptString = GetString("SaveDocumentAs")
+
+  fp.init(window, promptString, nsIFilePicker.modeSave);
+
+  // Set filters according to the type of output
+  if (aDoSaveAsText)
+    fp.appendFilters(nsIFilePicker.filterText);
+  else
+    fp.appendFilters(nsIFilePicker.filterHTML);
+  fp.appendFilters(nsIFilePicker.filterAll);
+
+  // now let's actually set the filepicker's suggested filename
+  var suggestedFileName = GetSuggestedFileName(aDocumentURLString, aMIMEType);
+  if (suggestedFileName)
+    fp.defaultString = suggestedFileName;
+
+  // set the file picker's current directory
+  // assuming we have information needed (like prior saved location)
+  try {
+    var ioService = GetIOService();
+    var fileHandler = GetFileProtocolHandler();
+    
+    var isLocalFile = true;
+    try {
+      var docURI = ioService.newURI(aDocumentURLString, GetCurrentEditor().documentCharacterSet, null);
+      isLocalFile = docURI.schemeIs("file");
+    }
+    catch (e) {}
+
+    var parentLocation = null;
+    if (isLocalFile)
+    {
+      var fileLocation = fileHandler.getFileFromURLSpec(aDocumentURLString); // this asserts if url is not local
+      parentLocation = fileLocation.parent;
+    }
+    if (parentLocation)
+    {
+      // Save current filepicker's default location
+      if ("gFilePickerDirectory" in window)
+        gFilePickerDirectory = fp.displayDirectory;
+
+      fp.displayDirectory = parentLocation;
+    }
+    else
+    {
+      // Initialize to the last-used directory for the particular type (saved in prefs)
+      SetFilePickerDirectory(fp, aEditorType);
+    }
+  }
+  catch(e) {}
+
+  dialogResult.filepickerClick = fp.show();
+  if (dialogResult.filepickerClick != nsIFilePicker.returnCancel)
+  {
+    // reset urlstring to new save location
+    dialogResult.resultingURIString = fileHandler.getURLSpecFromFile(fp.file);
+    dialogResult.resultingLocalFile = fp.file;
+    SaveFilePickerDirectory(fp, aEditorType);
+  }
+  else if ("gFilePickerDirectory" in window && gFilePickerDirectory)
+    fp.displayDirectory = gFilePickerDirectory; 
+
+  return dialogResult;
+}
+
+// returns a boolean (whether to continue (true) or not (false) because user canceled)
+function PromptAndSetTitleIfNone()
+{
+  if (GetDocumentTitle()) // we have a title; no need to prompt!
+    return true;
+
+  var promptService = GetPromptService();
+  if (!promptService) return false;
+
+  var result = {value:null};
+  var captionStr = GetString("DocumentTitle");
+  var msgStr = GetString("NeedDocTitle") + '\n' + GetString("DocTitleHelp");
+  var confirmed = promptService.prompt(window, captionStr, msgStr, result, null, {value:0});
+  if (confirmed)
+    SetDocumentTitle(TrimString(result.value));
+
+  return confirmed;
+}
+
+var gPersistObj;
+
+// Don't forget to do these things after calling OutputFileWithPersistAPI:
+// we need to update the uri before notifying listeners
+//    if (doUpdateURI)
+//      SetDocumentURI(docURI);
+//    UpdateWindowTitle();
+//    if (!aSaveCopy)
+//      editor.resetModificationCount();
+      // this should cause notification to listeners that document has changed
+
+const webPersist = Components.interfaces.nsIWebBrowserPersist;
+function OutputFileWithPersistAPI(editorDoc, aDestinationLocation, aRelatedFilesParentDir, aMimeType)
+{
+  gPersistObj = null;
+  var editor = GetCurrentEditor();
+  try {
+    var imeEditor = editor.QueryInterface(Components.interfaces.nsIEditorIMESupport);
+    imeEditor.forceCompositionEnd();
+    } catch (e) {}
+
+  var isLocalFile = false;
+  try {
+    var tmp1 = aDestinationLocation.QueryInterface(Components.interfaces.nsIFile);
+    isLocalFile = true;
+  } 
+  catch (e) {
+    try {
+      var tmp = aDestinationLocation.QueryInterface(Components.interfaces.nsIURI);
+      isLocalFile = tmp.schemeIs("file");
+    }
+    catch (e) {}
+  }
+
+  try {
+    // we should supply a parent directory if/when we turn on functionality to save related documents
+    var persistObj = Components.classes["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"].createInstance(webPersist);
+    persistObj.progressListener = gEditorOutputProgressListener;
+    
+    var wrapColumn = GetWrapColumn();
+    var outputFlags = GetOutputFlags(aMimeType, wrapColumn);
+
+    // for 4.x parity as well as improving readability of file locally on server
+    // this will always send crlf for upload (http/ftp)
+    if (!isLocalFile) // if we aren't saving locally then send both cr and lf
+    {
+      outputFlags |= webPersist.ENCODE_FLAGS_CR_LINEBREAKS | webPersist.ENCODE_FLAGS_LF_LINEBREAKS;
+
+      // we want to serialize the output for all remote publishing
+      // some servers can handle only one connection at a time
+      // some day perhaps we can make this user-configurable per site?
+      persistObj.persistFlags = persistObj.persistFlags | webPersist.PERSIST_FLAGS_SERIALIZE_OUTPUT;
+    }
+
+    // note: we always want to set the replace existing files flag since we have
+    // already given user the chance to not replace an existing file (file picker)
+    // or the user picked an option where the file is implicitly being replaced (save)
+    persistObj.persistFlags = persistObj.persistFlags 
+                            | webPersist.PERSIST_FLAGS_NO_BASE_TAG_MODIFICATIONS
+                            | webPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES
+                            | webPersist.PERSIST_FLAGS_DONT_FIXUP_LINKS
+                            | webPersist.PERSIST_FLAGS_DONT_CHANGE_FILENAMES
+                            | webPersist.PERSIST_FLAGS_FIXUP_ORIGINAL_DOM;
+    persistObj.saveDocument(editorDoc, aDestinationLocation, aRelatedFilesParentDir, 
+                            aMimeType, outputFlags, wrapColumn);
+    gPersistObj = persistObj;
+  }
+  catch(e) { dump("caught an error, bail\n"); return false; }
+
+  return true;
+}
+
+// returns output flags based on mimetype, wrapCol and prefs
+function GetOutputFlags(aMimeType, aWrapColumn)
+{
+  var outputFlags = 0;
+  var editor = GetCurrentEditor();
+  var outputEntity = (editor && editor.documentCharacterSet == "ISO-8859-1")
+    ? webPersist.ENCODE_FLAGS_ENCODE_LATIN1_ENTITIES
+    : webPersist.ENCODE_FLAGS_ENCODE_BASIC_ENTITIES;
+  if (aMimeType == "text/plain")
+  {
+    // When saving in "text/plain" format, always do formatting
+    outputFlags |= webPersist.ENCODE_FLAGS_FORMATTED;
+  }
+  else
+  {
+    try {
+      // Should we prettyprint? Check the pref
+      var prefs = GetPrefs();
+      if (prefs.getBoolPref("editor.prettyprint"))
+        outputFlags |= webPersist.ENCODE_FLAGS_FORMATTED;
+
+      // How much entity names should we output? Check the pref
+      var encodeEntity = prefs.getCharPref("editor.encode_entity");
+      switch (encodeEntity) {
+        case "basic"  : outputEntity = webPersist.ENCODE_FLAGS_ENCODE_BASIC_ENTITIES; break;
+        case "latin1" : outputEntity = webPersist.ENCODE_FLAGS_ENCODE_LATIN1_ENTITIES; break;
+        case "html"   : outputEntity = webPersist.ENCODE_FLAGS_ENCODE_HTML_ENTITIES; break;
+        case "none"   : outputEntity = 0; break;
+      }
+    }
+    catch (e) {}
+  }
+  outputFlags |= outputEntity;
+
+  if (aWrapColumn > 0)
+    outputFlags |= webPersist.ENCODE_FLAGS_WRAP;
+
+  return outputFlags;
+}
+
+// returns number of column where to wrap
+const nsIWebBrowserPersist = Components.interfaces.nsIWebBrowserPersist;
+function GetWrapColumn()
+{
+  try {
+    return GetCurrentEditor().wrapWidth;
+  } catch (e) {}
+  return 0;
+}
+
+function GetPromptService()
+{
+  var promptService;
+  try {
+    promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService();
+    promptService = promptService.QueryInterface(Components.interfaces.nsIPromptService);
+  }
+  catch (e) {}
+  return promptService;
+}
+
+const gShowDebugOutputStateChange = false;
+const gShowDebugOutputProgress = false;
+const gShowDebugOutputStatusChange = false;
+
+const gShowDebugOutputLocationChange = false;
+const gShowDebugOutputSecurityChange = false;
+
+const nsIWebProgressListener = Components.interfaces.nsIWebProgressListener;
+const nsIChannel = Components.interfaces.nsIChannel;
+
+const kErrorBindingAborted = 2152398850;
+const kErrorBindingRedirected = 2152398851;
+const kFileNotFound = 2152857618;
+
+var gEditorOutputProgressListener =
+{
+  onStateChange : function(aWebProgress, aRequest, aStateFlags, aStatus)
+  {
+    var editor = GetCurrentEditor();
+
+    // Use this to access onStateChange flags
+    var requestSpec;
+    try {
+      var channel = aRequest.QueryInterface(nsIChannel);
+      requestSpec = StripUsernamePasswordFromURI(channel.URI);
+    } catch (e) {
+      if ( gShowDebugOutputStateChange)
+        dump("***** onStateChange; NO REQUEST CHANNEL\n");
+    }
+
+    var pubSpec;
+    if (gPublishData)
+      pubSpec = gPublishData.publishUrl + gPublishData.docDir + gPublishData.filename;
+
+    if (gShowDebugOutputStateChange)
+    {
+      dump("\n***** onStateChange request: " + requestSpec + "\n");
+      dump("      state flags: ");
+
+      if (aStateFlags & nsIWebProgressListener.STATE_START)
+        dump(" STATE_START, ");
+      if (aStateFlags & nsIWebProgressListener.STATE_STOP)
+        dump(" STATE_STOP, ");
+      if (aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK)
+        dump(" STATE_IS_NETWORK ");
+
+      dump("\n * requestSpec="+requestSpec+", pubSpec="+pubSpec+", aStatus="+aStatus+"\n");
+
+      DumpDebugStatus(aStatus);
+    }
+    // The rest only concerns publishing, so bail out if no dialog
+    if (!gProgressDialog)
+      return;
+
+    // Detect start of file upload of any file:
+    // (We ignore any START messages after gPersistObj says publishing is finished
+    if ((aStateFlags & nsIWebProgressListener.STATE_START)
+         && gPersistObj && requestSpec
+         && (gPersistObj.currentState != gPersistObj.PERSIST_STATE_FINISHED))
+    {
+      try {
+        // Add url to progress dialog's list showing each file uploading
+        gProgressDialog.SetProgressStatus(GetFilename(requestSpec), "busy");
+      } catch(e) {}
+    }
+
+    // Detect end of file upload of any file:
+    if (aStateFlags & nsIWebProgressListener.STATE_STOP)
+    {
+      // ignore aStatus == kErrorBindingAborted; check http response for possible errors
+      try {
+        // check http channel for response: 200 range is ok; other ranges are not
+        var httpChannel = aRequest.QueryInterface(Components.interfaces.nsIHttpChannel);
+        var httpResponse = httpChannel.responseStatus;
+        if (httpResponse < 200 || httpResponse >= 300)
+          aStatus = httpResponse;   // not a real error but enough to pass check below
+        else if (aStatus == kErrorBindingAborted)
+          aStatus = 0;
+
+        if (gShowDebugOutputStateChange)
+          dump("http response is: "+httpResponse+"\n");
+      } 
+      catch(e) 
+      {
+        if (aStatus == kErrorBindingAborted)
+          aStatus = 0;
+      }
+
+      // We abort publishing for all errors except if image src file is not found
+      var abortPublishing = (aStatus != 0 && aStatus != kFileNotFound);
+
+      // Notify progress dialog when we receive the STOP
+      //  notification for a file if there was an error 
+      //  or a successful finish
+      //  (Check requestSpec to be sure message is for destination url)
+      if (aStatus != 0 
+           || (requestSpec && requestSpec.indexOf(GetScheme(gPublishData.publishUrl)) == 0))
+      {
+        try {
+          gProgressDialog.SetProgressFinished(GetFilename(requestSpec), aStatus);
+        } catch(e) {}
+      }
+
+
+      if (abortPublishing)
+      {
+        // Cancel publishing
+        gPersistObj.cancelSave();
+
+        // Don't do any commands after failure
+        gCommandAfterPublishing = null;
+
+        // Restore original document to undo image src url adjustments
+        if (gRestoreDocumentSource)
+        {
+          try {
+            editor.rebuildDocumentFromSource(gRestoreDocumentSource);
+
+            // Clear transaction cache since we just did a potentially 
+            //  very large insert and this will eat up memory
+            editor.transactionManager.clear();
+          }
+          catch (e) {}
+        }
+
+        // Notify progress dialog that we're finished
+        //  and keep open to show error
+        gProgressDialog.SetProgressFinished(null, 0);
+
+        // We don't want to change location or reset mod count, etc.
+        return;
+      }
+
+      //XXX HACK: "file://" protocol is not supported in network code
+      //    (bug 151867 filed to add this support, bug 151869 filed
+      //     to remove this and other code in nsIWebBrowserPersist)
+      //    nsIWebBrowserPersist *does* copy the file(s), but we don't 
+      //    get normal onStateChange messages.
+
+      // Case 1: If images are included, we get fairly normal
+      //    STATE_START/STATE_STOP & STATE_IS_NETWORK messages associated with the image files,
+      //    thus we must finish HTML file progress below
+
+      // Case 2: If just HTML file is uploaded, we get STATE_START and STATE_STOP
+      //    notification with a null "requestSpec", and 
+      //    the gPersistObj is destroyed before we get here!
+      //    So create an new object so we can flow through normal processing below
+      if (!requestSpec && GetScheme(gPublishData.publishUrl) == "file"
+          && (!gPersistObj || gPersistObj.currentState == nsIWebBrowserPersist.PERSIST_STATE_FINISHED))
+      {
+        aStateFlags |= nsIWebProgressListener.STATE_IS_NETWORK;
+        if (!gPersistObj)
+        {          
+          gPersistObj =
+          {
+            result : aStatus,
+            currentState : nsIWebBrowserPersist.PERSIST_STATE_FINISHED
+          }
+        }
+      }
+
+      // STATE_IS_NETWORK signals end of publishing, as does the gPersistObj.currentState
+      if (aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK
+          && gPersistObj.currentState == nsIWebBrowserPersist.PERSIST_STATE_FINISHED)
+      {
+        if (GetScheme(gPublishData.publishUrl) == "file")
+        {
+          //XXX "file://" hack: We don't get notified about the HTML file, so end progress for it
+          // (This covers both "Case 1 and 2" described above)
+          gProgressDialog.SetProgressFinished(gPublishData.filename, gPersistObj.result);
+        }
+
+        if (gPersistObj.result == 0)
+        {
+          // All files are finished and publishing succeeded (some images may have failed)
+          try {
+            // Make a new docURI from the "browse location" in case "publish location" was FTP
+            // We need to set document uri before notifying listeners
+            var docUrl = GetDocUrlFromPublishData(gPublishData);
+            SetDocumentURI(GetIOService().newURI(docUrl, editor.documentCharacterSet, null));
+
+            UpdateWindowTitle();
+
+            // this should cause notification to listeners that doc has changed
+            editor.resetModificationCount();
+
+            // Set UI based on whether we're editing a remote or local url
+            SetSaveAndPublishUI(urlstring);
+
+          } catch (e) {}
+
+          // Save publishData to prefs
+          if (gPublishData)
+          {
+            if (gPublishData.savePublishData)
+            {
+              // We published successfully, so we can safely
+              //  save docDir and otherDir to prefs
+              gPublishData.saveDirs = true;
+              SavePublishDataToPrefs(gPublishData);
+            }
+            else
+              SavePassword(gPublishData);
+          }
+
+          // Ask progress dialog to close, but it may not
+          // if user checked checkbox to keep it open
+          gProgressDialog.RequestCloseDialog();
+        }
+        else
+        {
+          // We previously aborted publishing because of error:
+          //   Calling gPersistObj.cancelSave() resulted in a non-zero gPersistObj.result,
+          //   so notify progress dialog we're finished
+          gProgressDialog.SetProgressFinished(null, 0);
+        }
+      }
+    }
+  },
+
+  onProgressChange : function(aWebProgress, aRequest, aCurSelfProgress,
+                              aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress)
+  {
+    if (!gPersistObj)
+      return;
+
+    if (gShowDebugOutputProgress)
+    {
+      dump("\n onProgressChange: gPersistObj.result="+gPersistObj.result+"\n");
+      try {
+      var channel = aRequest.QueryInterface(nsIChannel);
+      dump("***** onProgressChange request: " + channel.URI.spec + "\n");
+      }
+      catch (e) {}
+      dump("*****       self:  "+aCurSelfProgress+" / "+aMaxSelfProgress+"\n");
+      dump("*****       total: "+aCurTotalProgress+" / "+aMaxTotalProgress+"\n\n");
+
+      if (gPersistObj.currentState == gPersistObj.PERSIST_STATE_READY)
+        dump(" Persister is ready to save data\n\n");
+      else if (gPersistObj.currentState == gPersistObj.PERSIST_STATE_SAVING)
+        dump(" Persister is saving data.\n\n");
+      else if (gPersistObj.currentState == gPersistObj.PERSIST_STATE_FINISHED)
+        dump(" PERSISTER HAS FINISHED SAVING DATA\n\n\n");
+    }
+  },
+
+  onLocationChange : function(aWebProgress, aRequest, aLocation)
+  {
+    if (gShowDebugOutputLocationChange)
+    {
+      dump("***** onLocationChange: "+aLocation.spec+"\n");
+      try {
+        var channel = aRequest.QueryInterface(nsIChannel);
+        dump("*****          request: " + channel.URI.spec + "\n");
+      }
+      catch(e) {}
+    }
+  },
+
+  onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage)
+  {
+    if (gShowDebugOutputStatusChange)
+    {
+      dump("***** onStatusChange: "+aMessage+"\n");
+      try {
+        var channel = aRequest.QueryInterface(nsIChannel);
+        dump("*****        request: " + channel.URI.spec + "\n");
+      }
+      catch (e) { dump("          couldn't get request\n"); }
+      
+      DumpDebugStatus(aStatus);
+
+      if (gPersistObj)
+      {
+        if(gPersistObj.currentState == gPersistObj.PERSIST_STATE_READY)
+          dump(" Persister is ready to save data\n\n");
+        else if(gPersistObj.currentState == gPersistObj.PERSIST_STATE_SAVING)
+          dump(" Persister is saving data.\n\n");
+        else if(gPersistObj.currentState == gPersistObj.PERSIST_STATE_FINISHED)
+          dump(" PERSISTER HAS FINISHED SAVING DATA\n\n\n");
+      }
+    }
+  },
+
+  onSecurityChange : function(aWebProgress, aRequest, state)
+  {
+    if (gShowDebugOutputSecurityChange)
+    {
+      try {
+        var channel = aRequest.QueryInterface(nsIChannel);
+        dump("***** onSecurityChange request: " + channel.URI.spec + "\n");
+      } catch (e) {}
+    }
+  },
+
+  QueryInterface : function(aIID)
+  {
+    if (aIID.equals(Components.interfaces.nsIWebProgressListener)
+    || aIID.equals(Components.interfaces.nsISupports)
+    || aIID.equals(Components.interfaces.nsISupportsWeakReference)
+    || aIID.equals(Components.interfaces.nsIPrompt)
+    || aIID.equals(Components.interfaces.nsIAuthPrompt))
+      return this;
+    throw Components.results.NS_NOINTERFACE;
+  },
+
+// nsIPrompt
+  alert : function(dlgTitle, text)
+  {
+    AlertWithTitle(dlgTitle, text, gProgressDialog ? gProgressDialog : window);
+  },
+  alertCheck : function(dialogTitle, text, checkBoxLabel, checkObj)
+  {
+    AlertWithTitle(dialogTitle, text);
+  },
+  confirm : function(dlgTitle, text)
+  {
+    return ConfirmWithTitle(dlgTitle, text, null, null);
+  },
+  confirmCheck : function(dlgTitle, text, checkBoxLabel, checkObj)
+  {
+    var promptServ = GetPromptService();
+    if (!promptServ)
+      return;
+
+    promptServ.confirmEx(window, dlgTitle, text, nsIPromptService.STD_OK_CANCEL_BUTTONS,
+                         "", "", "", checkBoxLabel, checkObj);
+  },
+  confirmEx : function(dlgTitle, text, btnFlags, btn0Title, btn1Title, btn2Title, checkBoxLabel, checkVal)
+  {
+    var promptServ = GetPromptService();
+    if (!promptServ)
+     return 0;
+
+    return promptServ.confirmEx(window, dlgTitle, text, btnFlags,
+                        btn0Title, btn1Title, btn2Title,
+                        checkBoxLabel, checkVal);
+  },
+  prompt : function(dlgTitle, text, inoutText, checkBoxLabel, checkObj)
+  {
+    var promptServ = GetPromptService();
+    if (!promptServ)
+     return false;
+
+    return promptServ.prompt(window, dlgTitle, text, inoutText, checkBoxLabel, checkObj);
+  },
+  promptPassword : function(dlgTitle, text, pwObj, checkBoxLabel, savePWObj)
+  {
+
+    var promptServ = GetPromptService();
+    if (!promptServ)
+     return false;
+
+    var ret = false;
+    try {
+      // Note difference with nsIAuthPrompt::promptPassword, which has 
+      // just "in" savePassword param, while nsIPrompt is "inout"
+      // Initialize with user's previous preference for this site
+      if (gPublishData)
+        savePWObj.value = gPublishData.savePassword;
+
+      ret = promptServ.promptPassword(gProgressDialog ? gProgressDialog : window,
+                                      dlgTitle, text, pwObj, checkBoxLabel, savePWObj);
+
+      if (!ret)
+        setTimeout(CancelPublishing, 0);
+
+      if (ret && gPublishData)
+        UpdateUsernamePasswordFromPrompt(gPublishData, gPublishData.username, pwObj.value, savePWObj.value);
+    } catch(e) {}
+
+    return ret;
+  },
+  promptUsernameAndPassword : function(dlgTitle, text, userObj, pwObj, checkBoxLabel, savePWObj)
+  {
+    var ret = PromptUsernameAndPassword(dlgTitle, text, savePWObj.value, userObj, pwObj);
+    if (!ret)
+      setTimeout(CancelPublishing, 0);
+
+    return ret;
+  },
+  select : function(dlgTitle, text, count, selectList, outSelection)
+  {
+    var promptServ = GetPromptService();
+    if (!promptServ)
+      return false;
+
+    return promptServ.select(window, dlgTitle, text, count, selectList, outSelection);
+  },
+
+// nsIAuthPrompt
+  prompt : function(dlgTitle, text, pwrealm, savePW, defaultText, result)
+  {
+    var promptServ = GetPromptService();
+    if (!promptServ)
+      return false;
+
+    var savePWObj = {value:savePW};
+    var ret = promptServ.prompt(gProgressDialog ? gProgressDialog : window,
+                                dlgTitle, text, defaultText, pwrealm, savePWObj);
+    if (!ret)
+      setTimeout(CancelPublishing, 0);
+    return ret;
+  },
+
+  promptUsernameAndPassword : function(dlgTitle, text, pwrealm, savePW, userObj, pwObj)
+  {
+    var ret = PromptUsernameAndPassword(dlgTitle, text, savePW, userObj, pwObj);
+    if (!ret)
+      setTimeout(CancelPublishing, 0);
+    return ret;
+  },
+
+  promptPassword : function(dlgTitle, text, pwrealm, savePW, pwObj)
+  {
+    var ret = false;
+    try {
+      var promptServ = GetPromptService();
+      if (!promptServ)
+        return false;
+
+      // Note difference with nsIPrompt::promptPassword, which has 
+      // "inout" savePassword param, while nsIAuthPrompt is just "in"
+      // Also nsIAuth doesn't supply "checkBoxLabel"
+      // Initialize with user's previous preference for this site
+      var savePWObj = {value:savePW};
+      // Initialize with user's previous preference for this site
+      if (gPublishData)
+        savePWObj.value = gPublishData.savePassword;
+
+      ret = promptServ.promptPassword(gProgressDialog ? gProgressDialog : window,
+                                      dlgTitle, text, pwObj, GetString("SavePassword"), savePWObj);
+
+      if (!ret)
+        setTimeout(CancelPublishing, 0);
+
+      if (ret && gPublishData)
+        UpdateUsernamePasswordFromPrompt(gPublishData, gPublishData.username, pwObj.value, savePWObj.value);
+    } catch(e) {}
+
+    return ret;
+  }
+}
+
+function PromptUsernameAndPassword(dlgTitle, text, savePW, userObj, pwObj)
+{
+  // HTTP prompts us twice even if user Cancels from 1st attempt!
+  // So never put up dialog if there's no publish data
+  if (!gPublishData)
+    return false
+
+  var ret = false;
+  try {
+    var promptServ = GetPromptService();
+    if (!promptServ)
+      return false;
+
+    var savePWObj = {value:savePW};
+
+    // Initialize with user's previous preference for this site
+    if (gPublishData)
+    {
+      // HTTP put uses this dialog if either username or password is bad,
+      //   so prefill username input field with the previous value for modification
+      savePWObj.value = gPublishData.savePassword;
+      if (!userObj.value)
+        userObj.value = gPublishData.username;
+    }
+
+    ret = promptServ.promptUsernameAndPassword(gProgressDialog ? gProgressDialog : window, 
+                                               dlgTitle, text, userObj, pwObj, 
+                                               GetString("SavePassword"), savePWObj);
+    if (ret && gPublishData)
+      UpdateUsernamePasswordFromPrompt(gPublishData, userObj.value, pwObj.value, savePWObj.value);
+
+  } catch (e) {}
+
+  return ret;
+}
+
+function DumpDebugStatus(aStatus)
+{
+  // see nsError.h and netCore.h and ftpCore.h
+
+  if (aStatus == kErrorBindingAborted)
+    dump("***** status is NS_BINDING_ABORTED\n");
+  else if (aStatus == kErrorBindingRedirected)
+    dump("***** status is NS_BINDING_REDIRECTED\n");
+  else if (aStatus == 2152398859) // in netCore.h 11
+    dump("***** status is ALREADY_CONNECTED\n");
+  else if (aStatus == 2152398860) // in netCore.h 12
+    dump("***** status is NOT_CONNECTED\n");
+  else if (aStatus == 2152398861) //  in nsISocketTransportService.idl 13
+    dump("***** status is CONNECTION_REFUSED\n");
+  else if (aStatus == 2152398862) // in nsISocketTransportService.idl 14
+    dump("***** status is NET_TIMEOUT\n");
+  else if (aStatus == 2152398863) // in netCore.h 15
+    dump("***** status is IN_PROGRESS\n");
+  else if (aStatus == 2152398864) // 0x804b0010 in netCore.h 16
+    dump("***** status is OFFLINE\n");
+  else if (aStatus == 2152398865) // in netCore.h 17
+    dump("***** status is NO_CONTENT\n");
+  else if (aStatus == 2152398866) // in netCore.h 18
+    dump("***** status is UNKNOWN_PROTOCOL\n");
+  else if (aStatus == 2152398867) // in netCore.h 19
+    dump("***** status is PORT_ACCESS_NOT_ALLOWED\n");
+  else if (aStatus == 2152398868) // in nsISocketTransportService.idl 20
+    dump("***** status is NET_RESET\n");
+  else if (aStatus == 2152398869) // in ftpCore.h 21
+    dump("***** status is FTP_LOGIN\n");
+  else if (aStatus == 2152398870) // in ftpCore.h 22
+    dump("***** status is FTP_CWD\n");
+  else if (aStatus == 2152398871) // in ftpCore.h 23
+    dump("***** status is FTP_PASV\n");
+  else if (aStatus == 2152398872) // in ftpCore.h 24
+    dump("***** status is FTP_PWD\n");
+  else if (aStatus == 2152857601)
+    dump("***** status is UNRECOGNIZED_PATH\n");
+  else if (aStatus == 2152857602)
+    dump("***** status is UNRESOLABLE SYMLINK\n");
+  else if (aStatus == 2152857604)
+    dump("***** status is UNKNOWN_TYPE\n");
+  else if (aStatus == 2152857605)
+    dump("***** status is DESTINATION_NOT_DIR\n");
+  else if (aStatus == 2152857606)
+    dump("***** status is TARGET_DOES_NOT_EXIST\n");
+  else if (aStatus == 2152857608)
+    dump("***** status is ALREADY_EXISTS\n");
+  else if (aStatus == 2152857609)
+    dump("***** status is INVALID_PATH\n");
+  else if (aStatus == 2152857610)
+    dump("***** status is DISK_FULL\n");
+  else if (aStatus == 2152857612)
+    dump("***** status is NOT_DIRECTORY\n");
+  else if (aStatus == 2152857613)
+    dump("***** status is IS_DIRECTORY\n");
+  else if (aStatus == 2152857614)
+    dump("***** status is IS_LOCKED\n");
+  else if (aStatus == 2152857615)
+    dump("***** status is TOO_BIG\n");
+  else if (aStatus == 2152857616)
+    dump("***** status is NO_DEVICE_SPACE\n");
+  else if (aStatus == 2152857617)
+    dump("***** status is NAME_TOO_LONG\n");
+  else if (aStatus == 2152857618) // 80520012
+    dump("***** status is FILE_NOT_FOUND\n");
+  else if (aStatus == 2152857619)
+    dump("***** status is READ_ONLY\n");
+  else if (aStatus == 2152857620)
+    dump("***** status is DIR_NOT_EMPTY\n");
+  else if (aStatus == 2152857621)
+    dump("***** status is ACCESS_DENIED\n");
+  else if (aStatus == 2152398878)
+    dump("***** status is ? (No connection or time out?)\n");
+  else
+    dump("***** status is " + aStatus + "\n");
+}
+
+// Update any data that the user supplied in a prompt dialog
+function UpdateUsernamePasswordFromPrompt(publishData, username, password, savePassword)
+{
+  if (!publishData)
+    return;
+  
+  // Set flag to save publish data after publishing if it changed in dialog 
+  //  and the "SavePassword" checkbox was checked
+  //  or we already had site data for this site
+  // (Thus we don't automatically create a site until user brings up Publish As dialog)
+  publishData.savePublishData = (gPublishData.username != username || gPublishData.password != password)
+                                && (savePassword || !publishData.notInSiteData);
+
+  publishData.username = username;
+  publishData.password = password;
+  publishData.savePassword = savePassword;
+}
+
+const kSupportedTextMimeTypes =
+[
+  "text/plain",
+  "text/css",
+  "text/rdf",
+  "text/xsl",
+  "text/javascript",
+  "text/ecmascript",
+  "application/javascript",
+  "application/ecmascript",
+  "application/x-javascript",
+  "text/xul",
+  "application/vnd.mozilla.xul+xml"
+];
+
+function IsSupportedTextMimeType(aMimeType)
+{
+  for (var i = 0; i < kSupportedTextMimeTypes.length; i++)
+  {
+    if (kSupportedTextMimeTypes[i] == aMimeType)
+      return true;
+  }
+  return false;
+}
+
+// throws an error or returns true if user attempted save; false if user canceled save
+function SaveDocument(aSaveAs, aSaveCopy, aMimeType)
+{
+  var editor = GetCurrentEditor();
+  if (!aMimeType || aMimeType == "" || !editor)
+    throw Components.results.NS_ERROR_NOT_INITIALIZED;
+
+  var editorDoc = editor.document;
+  if (!editorDoc)
+    throw Components.results.NS_ERROR_NOT_INITIALIZED;
+
+  // if we don't have the right editor type bail (we handle text and html)
+  var editorType = GetCurrentEditorType();
+  if (editorType != "text" && editorType != "html" 
+      && editorType != "htmlmail" && editorType != "textmail")
+    throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
+
+  var saveAsTextFile = IsSupportedTextMimeType(aMimeType);
+
+  // check if the file is to be saved is a format we don't understand; if so, bail
+  if (aMimeType != "text/html" && !saveAsTextFile)
+    throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
+
+  if (saveAsTextFile)
+    aMimeType = "text/plain";
+
+  var urlstring = GetDocumentUrl();
+  var mustShowFileDialog = (aSaveAs || IsUrlAboutBlank(urlstring) || (urlstring == ""));
+
+  // If editing a remote URL, force SaveAs dialog
+  if (!mustShowFileDialog && GetScheme(urlstring) != "file")
+    mustShowFileDialog = true;
+
+  var replacing = !aSaveAs;
+  var titleChanged = false;
+  var doUpdateURI = false;
+  var tempLocalFile = null;
+
+  if (mustShowFileDialog)
+  {
+	  try {
+	    // Prompt for title if we are saving to HTML
+	    if (!saveAsTextFile && (editorType == "html"))
+	    {
+	      var userContinuing = PromptAndSetTitleIfNone(); // not cancel
+	      if (!userContinuing)
+	        return false;
+	    }
+
+	    var dialogResult = PromptForSaveLocation(saveAsTextFile, editorType, aMimeType, urlstring);
+	    if (dialogResult.filepickerClick == nsIFilePicker.returnCancel)
+	      return false;
+
+	    replacing = (dialogResult.filepickerClick == nsIFilePicker.returnReplace);
+	    urlstring = dialogResult.resultingURIString;
+	    tempLocalFile = dialogResult.resultingLocalFile;
+ 
+      // update the new URL for the webshell unless we are saving a copy
+      if (!aSaveCopy)
+        doUpdateURI = true;
+   } catch (e) {  return false; }
+  } // mustShowFileDialog
+
+  var success = true;
+  var ioService;
+  try {
+    // if somehow we didn't get a local file but we did get a uri, 
+    // attempt to create the localfile if it's a "file" url
+    var docURI;
+    if (!tempLocalFile)
+    {
+      ioService = GetIOService();
+      docURI = ioService.newURI(urlstring, editor.documentCharacterSet, null);
+      
+      if (docURI.schemeIs("file"))
+      {
+        var fileHandler = GetFileProtocolHandler();
+        tempLocalFile = fileHandler.getFileFromURLSpec(urlstring).QueryInterface(Components.interfaces.nsILocalFile);
+      }
+    }
+
+    // this is the location where the related files will go
+    var relatedFilesDir = null;
+    
+    // First check pref for saving associated files
+    var saveAssociatedFiles = false;
+    try {
+      var prefs = GetPrefs();
+      saveAssociatedFiles = prefs.getBoolPref("editor.save_associated_files");
+    } catch (e) {}
+
+    // Only change links or move files if pref is set 
+    //  and we are saving to a new location
+    if (saveAssociatedFiles && aSaveAs)
+    {
+      try {
+        if (tempLocalFile)
+        {
+          // if we are saving to the same parent directory, don't set relatedFilesDir
+          // grab old location, chop off file
+          // grab new location, chop off file, compare
+          var oldLocation = GetDocumentUrl();
+          var oldLocationLastSlash = oldLocation.lastIndexOf("\/");
+          if (oldLocationLastSlash != -1)
+            oldLocation = oldLocation.slice(0, oldLocationLastSlash);
+
+          var relatedFilesDirStr = urlstring;
+          var newLocationLastSlash = relatedFilesDirStr.lastIndexOf("\/");
+          if (newLocationLastSlash != -1)
+            relatedFilesDirStr = relatedFilesDirStr.slice(0, newLocationLastSlash);
+          if (oldLocation == relatedFilesDirStr || IsUrlAboutBlank(oldLocation))
+            relatedFilesDir = null;
+          else
+            relatedFilesDir = tempLocalFile.parent;
+        }
+        else
+        {
+          var lastSlash = urlstring.lastIndexOf("\/");
+          if (lastSlash != -1)
+          {
+            var relatedFilesDirString = urlstring.slice(0, lastSlash + 1);  // include last slash
+            ioService = GetIOService();
+            relatedFilesDir = ioService.newURI(relatedFilesDirString, editor.documentCharacterSet, null);
+          }
+        }
+      } catch(e) { relatedFilesDir = null; }
+    }
+
+    var destinationLocation;
+    if (tempLocalFile)
+      destinationLocation = tempLocalFile;
+    else
+      destinationLocation = docURI;
+
+    success = OutputFileWithPersistAPI(editorDoc, destinationLocation, relatedFilesDir, aMimeType);
+  }
+  catch (e)
+  {
+    success = false;
+  }
+
+  if (success)
+  {
+    try {
+      if (doUpdateURI)
+      {
+         // If a local file, we must create a new uri from nsILocalFile
+        if (tempLocalFile)
+          docURI = GetFileProtocolHandler().newFileURI(tempLocalFile);
+
+        // We need to set new document uri before notifying listeners
+        SetDocumentURI(docURI);
+      }
+
+      // Update window title to show possibly different filename
+      // This also covers problem that after undoing a title change,
+      //   window title loses the extra [filename] part that this adds
+      UpdateWindowTitle();
+
+      if (!aSaveCopy)
+        editor.resetModificationCount();
+      // this should cause notification to listeners that document has changed
+
+      // Set UI based on whether we're editing a remote or local url
+      SetSaveAndPublishUI(urlstring);
+    } catch (e) {}
+  }
+  else
+  {
+    var saveDocStr = GetString("SaveDocument");
+    var failedStr = GetString("SaveFileFailed");
+    AlertWithTitle(saveDocStr, failedStr);
+  }
+  return success;
+}
+
+function SetDocumentURI(uri)
+{
+  try {
+    // XXX WE'LL NEED TO GET "CURRENT" CONTENT FRAME ONCE MULTIPLE EDITORS ARE ALLOWED
+    GetCurrentEditorElement().docShell.setCurrentURI(uri);
+  } catch (e) { dump("SetDocumentURI:\n"+e +"\n"); }
+}
+
+
+//-------------------------------  Publishing
+var gPublishData;
+var gProgressDialog;
+var gCommandAfterPublishing = null;
+var gRestoreDocumentSource;
+
+function Publish(publishData)
+{
+  if (!publishData)
+    return false;
+
+  // Set data in global for username password requests
+  //  and to do "post saving" actions after monitoring nsIWebProgressListener messages
+  //  and we are sure file transfer was successful
+  gPublishData = publishData;
+
+  gPublishData.docURI = CreateURIFromPublishData(publishData, true);
+  if (!gPublishData.docURI)
+  {
+    AlertWithTitle(GetString("Publish"), GetString("PublishFailed"));
+    return false;
+  }
+
+  if (gPublishData.publishOtherFiles)
+    gPublishData.otherFilesURI = CreateURIFromPublishData(publishData, false);
+  else
+    gPublishData.otherFilesURI = null;
+
+  if (gShowDebugOutputStateChange)
+  {
+    dump("\n *** publishData: PublishUrl="+publishData.publishUrl+", BrowseUrl="+publishData.browseUrl+
+      ", Username="+publishData.username+", Dir="+publishData.docDir+
+      ", Filename="+publishData.filename+"\n");
+    dump(" * gPublishData.docURI.spec w/o pass="+StripPassword(gPublishData.docURI.spec)+", PublishOtherFiles="+gPublishData.publishOtherFiles+"\n");
+  }
+
+  // XXX Missing username will make FTP fail 
+  // and it won't call us for prompt dialog (bug 132320)
+  // (It does prompt if just password is missing)
+  // So we should do the prompt ourselves before trying to publish
+  if (GetScheme(publishData.publishUrl) == "ftp" && !publishData.username)
+  {
+    var message = GetString("PromptFTPUsernamePassword").replace(/%host%/, GetHost(publishData.publishUrl));
+    var savePWobj = {value:publishData.savePassword};
+    var userObj = {value:publishData.username};
+    var pwObj = {value:publishData.password};
+    if (!PromptUsernameAndPassword(GetString("Prompt"), message, savePWobj, userObj, pwObj))
+      return false; // User canceled out of dialog
+
+    // Reset data in URI objects
+    gPublishData.docURI.username = publishData.username;
+    gPublishData.docURI.password = publishData.password;
+
+    if (gPublishData.otherFilesURI)
+    {
+      gPublishData.otherFilesURI.username = publishData.username;
+      gPublishData.otherFilesURI.password = publishData.password;
+    }
+  }
+
+  try {
+    // We launch dialog as a dependent 
+    // Don't allow editing document!
+    SetDocumentEditable(false);
+
+    // Start progress monitoring
+    gProgressDialog =
+      window.openDialog("chrome://editor/content/EditorPublishProgress.xul", "_blank",
+                        "chrome,dependent,titlebar", gPublishData, gPersistObj);
+
+  } catch (e) {}
+
+  // Network transfer is often too quick for the progress dialog to be initialized
+  //  and we can completely miss messages for quickly-terminated bad URLs,
+  //  so we can't call OutputFileWithPersistAPI right away.
+  // StartPublishing() is called at the end of the dialog's onload method
+  return true;
+}
+
+function StartPublishing()
+{
+  var editor = GetCurrentEditor();
+  if (editor && gPublishData && gPublishData.docURI && gProgressDialog)
+  {
+    gRestoreDocumentSource = null;
+
+    // Save backup document since nsIWebBrowserPersist changes image src urls
+    // but we only need to do this if publishing images and other related files
+    if (gPublishData.otherFilesURI)
+    {
+      try {
+        gRestoreDocumentSource = 
+          editor.outputToString(editor.contentsMIMEType, kOutputEncodeW3CEntities);
+      } catch (e) {}
+    }
+
+    OutputFileWithPersistAPI(editor.document, 
+                             gPublishData.docURI, gPublishData.otherFilesURI, 
+                             editor.contentsMIMEType);
+    return gPersistObj;
+  }
+  return null;
+}
+
+function CancelPublishing()
+{
+  try {
+    gPersistObj.cancelSave();
+    gProgressDialog.SetProgressStatusCancel();
+  } catch (e) {}
+
+  // If canceling publishing do not do any commands after this    
+  gCommandAfterPublishing = null;
+
+  if (gProgressDialog)
+  {
+    // Close Progress dialog 
+    // (this will call FinishPublishing())
+    gProgressDialog.CloseDialog();
+  }
+  else
+    FinishPublishing();
+}
+
+function FinishPublishing()
+{
+  SetDocumentEditable(true);
+  gProgressDialog = null;
+  gPublishData = null;
+  gRestoreDocumentSource = null;
+
+  if (gCommandAfterPublishing)
+  {
+    // Be sure to null out the global now incase of trouble when executing command
+    var command = gCommandAfterPublishing;
+    gCommandAfterPublishing = null;
+    goDoCommand(command);
+  }
+}
+
+// Create a nsIURI object filled in with all required publishing info
+function CreateURIFromPublishData(publishData, doDocUri)
+{
+  if (!publishData || !publishData.publishUrl)
+    return null;
+
+  var URI;
+  try {
+    var spec = publishData.publishUrl;
+    if (doDocUri)
+      spec += FormatDirForPublishing(publishData.docDir) + publishData.filename; 
+    else
+      spec += FormatDirForPublishing(publishData.otherDir);
+
+    var ioService = GetIOService();
+    URI = ioService.newURI(spec, GetCurrentEditor().documentCharacterSet, null);
+
+    if (publishData.username)
+      URI.username = publishData.username;
+    if (publishData.password)
+      URI.password = publishData.password;
+  }
+  catch (e) {}
+
+  return URI;
+}
+
+// Resolve the correct "http:" document URL when publishing via ftp
+function GetDocUrlFromPublishData(publishData)
+{
+  if (!publishData || !publishData.filename || !publishData.publishUrl)
+    return "";
+
+  // If user was previously editing an "ftp" url, then keep that as the new scheme
+  var url;
+  var docScheme = GetScheme(GetDocumentUrl());
+
+  // Always use the "HTTP" address if available
+  // XXX Should we do some more validation here for bad urls???
+  // Let's at least check for a scheme!
+  if (!GetScheme(publishData.browseUrl))
+    url = publishData.publishUrl;
+  else
+    url = publishData.browseUrl;
+
+  url += FormatDirForPublishing(publishData.docDir) + publishData.filename;
+
+  if (GetScheme(url) == "ftp")
+    url = InsertUsernameIntoUrl(url, publishData.username);
+
+  return url;
+}
+
+function SetSaveAndPublishUI(urlstring)
+{
+  // Be sure enabled state of toolbar buttons are correct
+  goUpdateCommand("cmd_save");
+  goUpdateCommand("cmd_publish");
+}
+
+function SetDocumentEditable(isDocEditable)
+{
+  var editor = GetCurrentEditor();
+  if (editor && editor.document)
+  {
+    try {
+      var flags = editor.flags;
+      editor.flags = isDocEditable ?  
+            flags &= ~nsIPlaintextEditor.eEditorReadonlyMask :
+            flags | nsIPlaintextEditor.eEditorReadonlyMask;
+    } catch(e) {}
+
+    // update all commands
+    window.updateCommands("create");
+  }  
+}
+
+// ****** end of save / publish **********//
+
+//-----------------------------------------------------------------------------------
+var nsPublishSettingsCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    if (GetCurrentEditor())
+    {
+      // Launch Publish Settings dialog
+
+      window.ok = window.openDialog("chrome://editor/content/EditorPublishSettings.xul","_blank", "chrome,close,titlebar,modal", "");
+      window.content.focus();
+      return window.ok;
+    }
+    return false;
+  }
+}
+
+//-----------------------------------------------------------------------------------
+var nsRevertCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable() &&
+            IsDocumentModified() &&
+            !IsUrlAboutBlank(GetDocumentUrl()));
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    // Confirm with the user to abandon current changes
+    var promptService = GetPromptService();
+    if (promptService)
+    {
+      // Put the page title in the message string
+      var title = GetDocumentTitle();
+      if (!title)
+        title = GetString("untitled");
+
+      var msg = GetString("AbandonChanges").replace(/%title%/,title);
+
+      var result = promptService.confirmEx(window, GetString("RevertCaption"), msg,
+  						      (promptService.BUTTON_TITLE_REVERT * promptService.BUTTON_POS_0) +
+  						      (promptService.BUTTON_TITLE_CANCEL * promptService.BUTTON_POS_1),
+  						      null, null, null, null, {value:0});
+
+      // Reload page if first button (Revert) was pressed
+      if(result == 0)
+      {
+        CancelHTMLSource();
+        EditorLoadUrl(GetDocumentUrl());
+      }
+    }
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsCloseCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return GetCurrentEditor() != null;
+  },
+  
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    CloseWindow();
+  }
+};
+
+function CloseWindow()
+{
+  // Check to make sure document is saved. "true" means allow "Don't Save" button,
+  //   so user can choose to close without saving
+  if (CheckAndSaveDocument("cmd_close", true)) 
+  {
+    if (window.InsertCharWindow)
+      SwitchInsertCharToAnotherEditorOrClose();
+
+    try {
+      var basewin = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+                      .getInterface(Components.interfaces.nsIWebNavigation)
+                      .QueryInterface(Components.interfaces.nsIDocShellTreeItem)
+                      .treeOwner
+                      .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+                      .getInterface(Components.interfaces.nsIBaseWindow);
+      basewin.destroy();
+    } catch (e) {}
+  }
+}
+
+//-----------------------------------------------------------------------------------
+var nsOpenRemoteCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return true;    // we can always do this
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    var params = { browser: null, action: null, url: "" };
+    openDialog( "chrome://communicator/content/openLocation.xul", "_blank", "chrome,modal,titlebar", params);
+    var win = getTopWin();
+    switch (params.action) {
+      case "0": // current window
+        win.focus();
+        win.loadURI(params.url, null,
+                    nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP);
+        break;
+      case "1": // new window
+        openDialog(getBrowserURL(), "_blank", "all,dialog=no", params.url, null,
+                   null, nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP);
+        break;
+      case "2": // edit
+        editPage(params.url);
+        break;
+      case "3": // new tab
+        win.focus();
+        var browser = win.getBrowser();
+        browser.selectedTab = browser.addTab(params.url, null, null, false,
+                nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP);
+        break;
+      default:
+        window.content.focus();
+        break;
+    }
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsPreviewCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable() && 
+            IsHTMLEditor() && 
+            (DocumentHasBeenSaved() || IsDocumentModified()));
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+	  // Don't continue if user canceled during prompt for saving
+    // DocumentHasBeenSaved will test if we have a URL and suppress "Don't Save" button if not
+    if (!CheckAndSaveDocument("cmd_preview", DocumentHasBeenSaved()))
+	    return;
+
+    // Check if we saved again just in case?
+	  if (DocumentHasBeenSaved())
+    {
+      var browser;
+      try {
+        // Find a browser with this URL
+        var windowManager = Components.classes["@mozilla.org/appshell/window-mediator;1"].getService();
+        var windowManagerInterface = windowManager.QueryInterface(Components.interfaces.nsIWindowMediator);
+        var enumerator = windowManagerInterface.getEnumerator("navigator:browser");
+
+        var documentURI = GetDocumentUrl();
+        while ( enumerator.hasMoreElements() )
+        {
+          browser = enumerator.getNext().QueryInterface(Components.interfaces.nsIDOMWindowInternal);
+          if ( browser && (documentURI == browser.getBrowser().currentURI.spec))
+            break;
+
+          browser = null;
+        }
+      }
+      catch (ex) {}
+
+      // If none found, open a new browser
+      if (!browser)
+      {
+        browser = window.openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no", documentURI);
+      }
+      else
+      {
+        try {
+          browser.BrowserReloadSkipCache();
+          browser.focus();
+        } catch (ex) {}
+      }
+    }
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsSendPageCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable() &&
+            (DocumentHasBeenSaved() || IsDocumentModified()));
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    // Don't continue if user canceled during prompt for saving
+    // DocumentHasBeenSaved will test if we have a URL and suppress "Don't Save" button if not
+    if (!CheckAndSaveDocument("cmd_editSendPage", DocumentHasBeenSaved()))
+	    return;
+
+    // Check if we saved again just in case?
+    if (DocumentHasBeenSaved())
+    {
+      // Launch Messenger Composer window with current page as contents
+      try
+      {
+        openComposeWindow(GetDocumentUrl(), GetDocumentTitle());        
+      } catch (ex) { dump("Cannot Send Page: " + ex + "\n"); }
+    }
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsPrintCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return true;    // we can always do this
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    // In editor.js
+    FinishHTMLSource();
+    try {
+      PrintUtils.print();
+    } catch (e) {}
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsPrintSetupCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return true;    // we can always do this
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    // In editor.js
+    FinishHTMLSource();
+    PrintUtils.showPageSetup();
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsQuitCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return true;    // we can always do this
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {}
+
+  /* The doCommand is not used, since cmd_quit's oncommand="goQuitApplication()" in platformCommunicatorOverlay.xul
+  doCommand: function(aCommand)
+  {
+    // In editor.js
+    FinishHTMLSource();
+    goQuitApplication();
+  }
+  */
+};
+
+//-----------------------------------------------------------------------------------
+var nsFindCommand =
+{
+  isCommandEnabled: function(aCommand, editorElement)
+  {
+    return editorElement.getEditor(editorElement.contentWindow) != null;
+  },
+
+  getCommandStateParams: function(aCommand, aParams, editorElement) {},
+  doCommandParams: function(aCommand, aParams, editorElement) {},
+
+  doCommand: function(aCommand, editorElement)
+  {
+    try {
+      window.openDialog("chrome://editor/content/EdReplace.xul", "_blank",
+                        "chrome,modal,titlebar", editorElement);
+    }
+    catch(ex) {
+      dump("*** Exception: couldn't open Replace Dialog\n");
+    }
+    //window.content.focus();
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsFindAgainCommand =
+{
+  isCommandEnabled: function(aCommand, editorElement)
+  {
+    // we can only do this if the search pattern is non-empty. Not sure how
+    // to get that from here
+    return editorElement.getEditor(editorElement.contentWindow) != null;
+  },
+
+  getCommandStateParams: function(aCommand, aParams, editorElement) {},
+  doCommandParams: function(aCommand, aParams, editorElement) {},
+
+  doCommand: function(aCommand, editorElement)
+  {
+    try {
+      var findPrev = aCommand == "cmd_findPrev";
+      var findInst = editorElement.webBrowserFind;
+      var findService = Components.classes["@mozilla.org/find/find_service;1"]
+                                  .getService(Components.interfaces.nsIFindService);
+      findInst.findBackwards = findService.findBackwards ^ findPrev;
+      findInst.findNext();
+      // reset to what it was in dialog, otherwise dialog setting can get reversed
+      findInst.findBackwards = findService.findBackwards; 
+    }
+    catch (ex) {}
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsRewrapCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable() && !IsInHTMLSourceMode() &&
+            GetCurrentEditor() instanceof Components.interfaces.nsIEditorMailSupport);
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    GetCurrentEditor().QueryInterface(Components.interfaces.nsIEditorMailSupport).rewrap(false);
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsSpellingCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable() && 
+            !IsInHTMLSourceMode() && IsSpellCheckerInstalled());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    window.cancelSendMessage = false;
+    try {
+      var skipBlockQuotes = (window.document.documentElement.getAttribute("windowtype") == "msgcompose");
+      window.openDialog("chrome://editor/content/EdSpellCheck.xul", "_blank",
+              "chrome,close,titlebar,modal", false, skipBlockQuotes, true);
+    }
+    catch(ex) {}
+    window.content.focus();
+  }
+};
+
+// Validate using http://validator.w3.org/file-upload.html
+var URL2Validate;
+var nsValidateCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return GetCurrentEditor() != null;
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    // If the document hasn't been modified,
+    // then just validate the current url.
+    if (IsDocumentModified() || IsHTMLSourceChanged())
+    {
+      if (!CheckAndSaveDocument("cmd_validate", false))
+        return;
+
+      // Check if we saved again just in case?
+      if (!DocumentHasBeenSaved())    // user hit cancel?
+        return;
+    }
+
+    URL2Validate = GetDocumentUrl();
+    // See if it's a file:
+    var ifile;
+    try {
+      var fileHandler = GetFileProtocolHandler();
+      ifile = fileHandler.getFileFromURLSpec(URL2Validate);
+      // nsIFile throws an exception if it's not a file url
+    } catch (e) { ifile = null; }
+    if (ifile)
+    {
+      URL2Validate = ifile.path;
+      var vwin = window.open("http://validator.w3.org/file-upload.html",
+                             "EditorValidate");
+      // Window loads asynchronously, so pass control to the load listener:
+      vwin.addEventListener("load", this.validateFilePageLoaded, false);
+    }
+    else
+    {
+      var vwin2 = window.open("http://validator.w3.org/check?uri="
+                              + URL2Validate
+                              + "&doctype=Inline",
+                              "EditorValidate");
+      // This does the validation, no need to wait for page loaded.
+    }
+  },
+  validateFilePageLoaded: function(event)
+  {
+    event.target.forms[0].uploaded_file.value = URL2Validate;
+  }
+};
+
+var nsCheckLinksCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    window.openDialog("chrome://editor/content/EdLinkChecker.xul","_blank", "chrome,close,titlebar,modal");
+    window.content.focus();
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsFormCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable() && IsEditingRenderedHTML());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    window.openDialog("chrome://editor/content/EdFormProps.xul", "_blank", "chrome,close,titlebar,modal");
+    window.content.focus();
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsInputTagCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable() && IsEditingRenderedHTML());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    window.openDialog("chrome://editor/content/EdInputProps.xul", "_blank", "chrome,close,titlebar,modal");
+    window.content.focus();
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsInputImageCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable() && IsEditingRenderedHTML());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    window.openDialog("chrome://editor/content/EdInputImage.xul", "_blank", "chrome,close,titlebar,modal");
+    window.content.focus();
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsTextAreaCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable() && IsEditingRenderedHTML());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    window.openDialog("chrome://editor/content/EdTextAreaProps.xul", "_blank", "chrome,close,titlebar,modal");
+    window.content.focus();
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsSelectCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable() && IsEditingRenderedHTML());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    window.openDialog("chrome://editor/content/EdSelectProps.xul", "_blank", "chrome,close,titlebar,modal");
+    window.content.focus();
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsButtonCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable() && IsEditingRenderedHTML());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    window.openDialog("chrome://editor/content/EdButtonProps.xul", "_blank", "chrome,close,titlebar,modal");
+    window.content.focus();
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsLabelCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable() && IsEditingRenderedHTML());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    var tagName = "label";
+    try {
+      var editor = GetCurrentEditor();
+      // Find selected label or if start/end of selection is in label 
+      var labelElement = editor.getSelectedElement(tagName);
+      if (!labelElement)
+        labelElement = editor.getElementOrParentByTagName(tagName, editor.selection.anchorNode);
+      if (!labelElement)
+        labelElement = editor.getElementOrParentByTagName(tagName, editor.selection.focusNode);
+      if (labelElement) {
+        // We only open the dialog for an existing label
+        window.openDialog("chrome://editor/content/EdLabelProps.xul", "_blank", "chrome,close,titlebar,modal", labelElement);
+        window.content.focus();
+      } else {
+        EditorSetTextProperty(tagName, "", "");
+      }
+    } catch (e) {}
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsFieldSetCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable() && IsEditingRenderedHTML());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    window.openDialog("chrome://editor/content/EdFieldSetProps.xul", "_blank", "chrome,close,titlebar,modal");
+    window.content.focus();
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsIsIndexCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable() && IsEditingRenderedHTML());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    try {
+      var editor = GetCurrentEditor();
+      var isindexElement = editor.createElementWithDefaults("isindex");
+      isindexElement.setAttribute("prompt", editor.outputToString("text/plain", kOutputSelectionOnly));
+      editor.insertElementAtSelection(isindexElement, true);
+    } catch (e) {}
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsImageCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable() && IsEditingRenderedHTML());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    window.openDialog("chrome://editor/content/EdImageProps.xul","_blank", "chrome,close,titlebar,modal");
+    window.content.focus();
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsHLineCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable() && IsEditingRenderedHTML());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    // Inserting an HLine is different in that we don't use properties dialog
+    //  unless we are editing an existing line's attributes
+    //  We get the last-used attributes from the prefs and insert immediately
+
+    var tagName = "hr";
+    var editor = GetCurrentEditor();
+      
+    var hLine;
+    try {
+      hLine = editor.getSelectedElement(tagName);
+    } catch (e) {return;}
+
+    if (hLine)
+    {
+      // We only open the dialog for an existing HRule
+      window.openDialog("chrome://editor/content/EdHLineProps.xul", "_blank", "chrome,close,titlebar,modal");
+      window.content.focus();
+    } 
+    else
+    {
+      try {
+        hLine = editor.createElementWithDefaults(tagName);
+
+        // We change the default attributes to those saved in the user prefs
+        var prefs = GetPrefs();
+        var align = prefs.getIntPref("editor.hrule.align");
+        if (align == 0)
+          editor.setAttributeOrEquivalent(hLine, "align", "left", true);
+        else if (align == 2)
+          editor.setAttributeOrEquivalent(hLine, "align", "right", true);
+
+        //Note: Default is center (don't write attribute)
+  
+        var width = prefs.getIntPref("editor.hrule.width");
+        var percent = prefs.getBoolPref("editor.hrule.width_percent");
+        if (percent)
+          width = width +"%";
+
+        editor.setAttributeOrEquivalent(hLine, "width", width, true);
+
+        var height = prefs.getIntPref("editor.hrule.height");
+        editor.setAttributeOrEquivalent(hLine, "size", String(height), true);
+
+        var shading = prefs.getBoolPref("editor.hrule.shading");
+        if (shading)
+          hLine.removeAttribute("noshade");
+        else
+          hLine.setAttribute("noshade", "noshade");
+
+        editor.insertElementAtSelection(hLine, true);
+
+      } catch (e) {}
+    }
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsLinkCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable() && IsEditingRenderedHTML());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    // If selected element is an image, launch that dialog instead 
+    // since last tab panel handles link around an image
+    var element = GetObjectForProperties();
+    if (element && element.nodeName.toLowerCase() == "img")
+      window.openDialog("chrome://editor/content/EdImageProps.xul","_blank", "chrome,close,titlebar,modal", null, true);
+    else
+      window.openDialog("chrome://editor/content/EdLinkProps.xul","_blank", "chrome,close,titlebar,modal");
+    window.content.focus();
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsAnchorCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable() && IsEditingRenderedHTML());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    window.openDialog("chrome://editor/content/EdNamedAnchorProps.xul", "_blank", "chrome,close,titlebar,modal", "");
+    window.content.focus();
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsInsertHTMLWithDialogCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable() && IsEditingRenderedHTML());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    window.openDialog("chrome://editor/content/EdInsSrc.xul","_blank", "chrome,close,titlebar,modal,resizable", "");
+    window.content.focus();
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsInsertCharsCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    EditorFindOrCreateInsertCharWindow();
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsInsertBreakCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable() && IsEditingRenderedHTML());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    try {
+      GetCurrentEditor().insertHTML("<br>");
+    } catch (e) {}
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsInsertBreakAllCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable() && IsEditingRenderedHTML());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    try {
+      GetCurrentEditor().insertHTML("<br clear='all'>");
+    } catch (e) {}
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsGridCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable() && IsEditingRenderedHTML());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    window.openDialog("chrome://editor/content/EdSnapToGrid.xul","_blank", "chrome,close,titlebar,modal");
+    window.content.focus();
+  }
+};
+
+
+//-----------------------------------------------------------------------------------
+var nsListPropertiesCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable() && IsEditingRenderedHTML());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    window.openDialog("chrome://editor/content/EdListProps.xul","_blank", "chrome,close,titlebar,modal");
+    window.content.focus();
+  }
+};
+
+
+//-----------------------------------------------------------------------------------
+var nsPagePropertiesCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable() && IsEditingRenderedHTML());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    var oldTitle = GetDocumentTitle();
+    window.openDialog("chrome://editor/content/EdPageProps.xul","_blank", "chrome,close,titlebar,modal", "");
+
+    // Update main window title and 
+    // recent menu data in prefs if doc title changed
+    if (GetDocumentTitle() != oldTitle)
+      UpdateWindowTitle();
+
+    window.content.focus();
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsObjectPropertiesCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    var isEnabled = false;
+    if (IsDocumentEditable() && IsEditingRenderedHTML())
+    {
+      isEnabled = (GetObjectForProperties() != null ||
+                   GetCurrentEditor().getSelectedElement("href") != null);
+    }
+    return isEnabled;
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    // Launch Object properties for appropriate selected element 
+    var element = GetObjectForProperties();
+    if (element)
+    {
+      var name = element.nodeName.toLowerCase();
+      switch (name)
+      {
+        case 'img':
+          goDoCommand("cmd_image");
+          break;
+        case 'hr':
+          goDoCommand("cmd_hline");
+          break;
+        case 'form':
+          goDoCommand("cmd_form");
+          break;
+        case 'input':
+          var type = element.getAttribute("type");
+          if (type && type.toLowerCase() == "image")
+            goDoCommand("cmd_inputimage");
+          else
+            goDoCommand("cmd_inputtag");
+          break;
+        case 'textarea':
+          goDoCommand("cmd_textarea");
+          break;
+        case 'select':
+          goDoCommand("cmd_select");
+          break;
+        case 'button':
+          goDoCommand("cmd_button");
+          break;
+        case 'label':
+          goDoCommand("cmd_label");
+          break;
+        case 'fieldset':
+          goDoCommand("cmd_fieldset");
+          break;
+        case 'table':
+          EditorInsertOrEditTable(false);
+          break;
+        case 'td':
+        case 'th':
+          EditorTableCellProperties();
+          break;
+        case 'ol':
+        case 'ul':
+        case 'dl':
+        case 'li':
+          goDoCommand("cmd_listProperties");
+          break;
+        case 'a':
+          if (element.name)
+          {
+            goDoCommand("cmd_anchor");
+          }
+          else if(element.href)
+          {
+            goDoCommand("cmd_link");
+          }
+          break;
+        default:
+          doAdvancedProperties(element);
+          break;
+      }
+    } else {
+      // We get a partially-selected link if asked for specifically
+      try {
+        element = GetCurrentEditor().getSelectedElement("href");
+      } catch (e) {}
+      if (element)
+        goDoCommand("cmd_link");
+    }
+    window.content.focus();
+  }
+};
+
+
+//-----------------------------------------------------------------------------------
+var nsSetSmiley =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable() && IsEditingRenderedHTML());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon)
+  {
+    var smileyCode = aParams.getStringValue("state_attribute");
+
+    var strSml;
+    switch(smileyCode)
+    {
+        case ":-)": strSml="s1";
+        break;
+        case ":-(": strSml="s2";
+        break;
+        case ";-)": strSml="s3";
+        break;
+        case ":-P":
+        case ":-p":
+        case ":-b": strSml="s4";
+        break;
+        case ":-D": strSml="s5";
+        break;
+        case ":-[": strSml="s6";
+        break;
+        case ":-/":
+        case ":/":
+        case ":-\\":
+        case ":\\": strSml="s7";
+        break;
+        case "=-O":
+        case "=-o": strSml="s8";
+        break;
+        case ":-*": strSml="s9";
+        break;
+        case ">:o":
+        case ">:-o": strSml="s10";
+        break;
+        case "8-)": strSml="s11";
+        break;
+        case ":-$": strSml="s12";
+        break;
+        case ":-!": strSml="s13";
+        break;
+        case "O:-)":
+        case "o:-)": strSml="s14";
+        break;
+        case ":'(": strSml="s15";
+        break;
+        case ":-X":
+        case ":-x": strSml="s16";
+        break;
+        default:	strSml="";
+        break;
+    }
+
+    try
+    {
+      var editor = GetCurrentEditor();
+      var selection = editor.selection;
+      var extElement = editor.createElementWithDefaults("span");
+      extElement.setAttribute("class", "moz-smiley-" + strSml);
+
+      var intElement = editor.createElementWithDefaults("span");
+      if (!intElement)
+        return;
+
+      //just for mailnews, because of the way it removes HTML
+      var smileButMenu = document.getElementById('smileButtonMenu');      
+      if (smileButMenu.getAttribute("padwithspace"))
+         smileyCode = " " + smileyCode + " ";
+
+      var txtElement =  editor.document.createTextNode(smileyCode);
+      if (!txtElement)
+        return;
+
+      intElement.appendChild (txtElement);
+      extElement.appendChild (intElement);
+
+
+      editor.insertElementAtSelection(extElement,true);
+      window.content.focus();		
+
+    } 
+    catch (e) 
+    {
+        dump("Exception occured in smiley InsertElementAtSelection\n");
+    }
+  },
+  // This is now deprecated in favor of "doCommandParams"
+  doCommand: function(aCommand) {}
+};
+
+
+function doAdvancedProperties(element)
+{
+  if (element)
+  {
+    window.openDialog("chrome://editor/content/EdAdvancedEdit.xul", "_blank", "chrome,close,titlebar,modal,resizable=yes", "", element);
+    window.content.focus();
+  }
+}
+
+var nsAdvancedPropertiesCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable() && IsEditingRenderedHTML());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    // Launch AdvancedEdit dialog for the selected element
+    try {
+      var element = GetCurrentEditor().getSelectedElement("");
+      doAdvancedProperties(element);
+    } catch (e) {}
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsColorPropertiesCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable() && IsEditingRenderedHTML());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    window.openDialog("chrome://editor/content/EdColorProps.xul","_blank", "chrome,close,titlebar,modal", ""); 
+    UpdateDefaultColors(); 
+    window.content.focus();
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsRemoveNamedAnchorsCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    // We could see if there's any link in selection, but it doesn't seem worth the work!
+    return (IsDocumentEditable() && IsEditingRenderedHTML());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    EditorRemoveTextProperty("name", "");
+    window.content.focus();
+  }
+};
+
+
+//-----------------------------------------------------------------------------------
+var nsEditLinkCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    // Not really used -- this command is only in context menu, and we do enabling there
+    return (IsDocumentEditable() && IsEditingRenderedHTML());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    try {
+      var element = GetCurrentEditor().getSelectedElement("href");
+      if (element)
+        editPage(element.href, window, false);
+    } catch (e) {}
+    window.content.focus();
+  }
+};
+
+
+//-----------------------------------------------------------------------------------
+var nsNormalModeCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return IsHTMLEditor() && IsDocumentEditable();
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    SetEditMode(kDisplayModeNormal);
+  }
+};
+
+var nsAllTagsModeCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable() && IsHTMLEditor());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    SetEditMode(kDisplayModeAllTags);
+  }
+};
+
+var nsHTMLSourceModeCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable() && IsHTMLEditor());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    SetEditMode(kDisplayModeSource);
+  }
+};
+
+var nsPreviewModeCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable() && IsHTMLEditor());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    SetEditMode(kDisplayModePreview);
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsInsertOrEditTableCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return (IsDocumentEditable() && IsEditingRenderedHTML());
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    if (IsInTableCell())
+      EditorTableCellProperties();
+    else
+      EditorInsertOrEditTable(true);
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsEditTableCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return IsInTable();
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    EditorInsertOrEditTable(false);
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsSelectTableCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return IsInTable();
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    try {
+      GetCurrentTableEditor().selectTable();
+    } catch(e) {}
+    window.content.focus();
+  }
+};
+
+var nsSelectTableRowCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return IsInTableCell();
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    try {
+      GetCurrentTableEditor().selectTableRow();
+    } catch(e) {}
+    window.content.focus();
+  }
+};
+
+var nsSelectTableColumnCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return IsInTableCell();
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    try {
+      GetCurrentTableEditor().selectTableColumn();
+    } catch(e) {}
+    window.content.focus();
+  }
+};
+
+var nsSelectTableCellCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return IsInTableCell();
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    try {
+      GetCurrentTableEditor().selectTableCell();
+    } catch(e) {}
+    window.content.focus();
+  }
+};
+
+var nsSelectAllTableCellsCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return IsInTable();
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    try {
+      GetCurrentTableEditor().selectAllTableCells();
+    } catch(e) {}
+    window.content.focus();
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsInsertTableCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return IsDocumentEditable() && IsEditingRenderedHTML();
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    EditorInsertTable();
+  }
+};
+
+var nsInsertTableRowAboveCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return IsInTableCell();
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    try {
+      GetCurrentTableEditor().insertTableRow(1, false);
+    } catch(e) {}
+    window.content.focus();
+  }
+};
+
+var nsInsertTableRowBelowCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return IsInTableCell();
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    try {
+      GetCurrentTableEditor().insertTableRow(1, true);
+    } catch(e) {}
+    window.content.focus();
+  }
+};
+
+var nsInsertTableColumnBeforeCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return IsInTableCell();
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    try {
+      GetCurrentTableEditor().insertTableColumn(1, false);
+    } catch(e) {}
+    window.content.focus();
+  }
+};
+
+var nsInsertTableColumnAfterCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return IsInTableCell();
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    try {
+      GetCurrentTableEditor().insertTableColumn(1, true);
+    } catch(e) {}
+    window.content.focus();
+  }
+};
+
+var nsInsertTableCellBeforeCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return IsInTableCell();
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    try {
+      GetCurrentTableEditor().insertTableCell(1, false);
+    } catch(e) {}
+    window.content.focus();
+  }
+};
+
+var nsInsertTableCellAfterCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return IsInTableCell();
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    try {
+      GetCurrentTableEditor().insertTableCell(1, true);
+    } catch(e) {}
+    window.content.focus();
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsDeleteTableCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return IsInTable();
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    try {
+      GetCurrentTableEditor().deleteTable();
+    } catch(e) {}
+    window.content.focus();
+  }
+};
+
+var nsDeleteTableRowCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return IsInTableCell();
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    var rows = GetNumberOfContiguousSelectedRows();
+    // Delete at least one row
+    if (rows == 0)
+      rows = 1;
+
+    try {
+      var editor = GetCurrentTableEditor();
+      editor.beginTransaction();
+
+      // Loop to delete all blocks of contiguous, selected rows
+      while (rows)
+      {
+        editor.deleteTableRow(rows);
+        rows = GetNumberOfContiguousSelectedRows();
+      }
+    } finally { editor.endTransaction(); }
+    window.content.focus();
+  }
+};
+
+var nsDeleteTableColumnCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return IsInTableCell();
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    var columns = GetNumberOfContiguousSelectedColumns();
+    // Delete at least one column
+    if (columns == 0)
+      columns = 1;
+
+    try {
+      var editor = GetCurrentTableEditor();
+      editor.beginTransaction();
+
+      // Loop to delete all blocks of contiguous, selected columns
+      while (columns)
+      {
+        editor.deleteTableColumn(columns);
+        columns = GetNumberOfContiguousSelectedColumns();
+      }
+    } finally { editor.endTransaction(); }
+    window.content.focus();
+  }
+};
+
+var nsDeleteTableCellCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return IsInTableCell();
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    try {
+      GetCurrentTableEditor().deleteTableCell(1);   
+    } catch (e) {}
+    window.content.focus();
+  }
+};
+
+var nsDeleteTableCellContentsCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return IsInTableCell();
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    try {
+      GetCurrentTableEditor().deleteTableCellContents();
+    } catch (e) {}
+    window.content.focus();
+  }
+};
+
+
+//-----------------------------------------------------------------------------------
+var nsNormalizeTableCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return IsInTable();
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    // Use nsnull to let editor find table enclosing current selection
+    try {
+      GetCurrentTableEditor().normalizeTable(null);   
+    } catch (e) {}
+    window.content.focus();
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsJoinTableCellsCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    if (IsDocumentEditable() && IsEditingRenderedHTML())
+    {
+      try {
+        var editor = GetCurrentTableEditor();
+        var tagNameObj = { value: "" };
+        var countObj = { value: 0 };
+        var cell = editor.getSelectedOrParentTableElement(tagNameObj, countObj);
+
+        // We need a cell and either > 1 selected cell or a cell to the right
+        //  (this cell may originate in a row spanned from above current row)
+        // Note that editor returns "td" for "th" also.
+        // (this is a pain! Editor and gecko use lowercase tagNames, JS uses uppercase!)
+        if( cell && (tagNameObj.value == "td"))
+        {
+          // Selected cells
+          if (countObj.value > 1) return true;
+
+          var colSpan = cell.getAttribute("colspan");
+
+          // getAttribute returns string, we need number
+          // no attribute means colspan = 1
+          if (!colSpan)
+            colSpan = Number(1);
+          else
+            colSpan = Number(colSpan);
+
+          var rowObj = { value: 0 };
+          var colObj = { value: 0 };
+          editor.getCellIndexes(cell, rowObj, colObj);
+
+          // Test if cell exists to the right of current cell
+          // (cells with 0 span should never have cells to the right
+          //  if there is, user can select the 2 cells to join them)
+          return (colSpan && editor.getCellAt(null, rowObj.value,
+                                              colObj.value + colSpan));
+        }
+      } catch (e) {}
+    }
+    return false;
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    // Param: Don't merge non-contiguous cells
+    try {
+      GetCurrentTableEditor().joinTableCells(false);
+    } catch (e) {}
+    window.content.focus();
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsSplitTableCellCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    if (IsDocumentEditable() && IsEditingRenderedHTML())
+    {
+      var tagNameObj = { value: "" };
+      var countObj = { value: 0 };
+      var cell;
+      try {
+        cell = GetCurrentTableEditor().getSelectedOrParentTableElement(tagNameObj, countObj);
+      } catch (e) {}
+
+      // We need a cell parent and there's just 1 selected cell 
+      // or selection is entirely inside 1 cell
+      if ( cell && (tagNameObj.value == "td") && 
+           countObj.value <= 1 &&
+           IsSelectionInOneCell() )
+      {
+        var colSpan = cell.getAttribute("colspan");
+        var rowSpan = cell.getAttribute("rowspan");
+        if (!colSpan) colSpan = 1;
+        if (!rowSpan) rowSpan = 1;
+        return (colSpan > 1  || rowSpan > 1 ||
+                colSpan == 0 || rowSpan == 0);
+      }
+    }
+    return false;
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    try {
+      GetCurrentTableEditor().splitTableCell();
+    } catch (e) {}
+    window.content.focus();
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsTableOrCellColorCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return IsInTable();
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    EditorSelectColor("TableOrCell");
+  }
+};
+
+//-----------------------------------------------------------------------------------
+var nsPreferencesCommand =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return true;
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    goPreferences('composer_pane');
+    window.content.focus();
+  }
+};
+
+
+var nsFinishHTMLSource =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return true;
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    // In editor.js
+    FinishHTMLSource();
+  }
+};
+
+var nsCancelHTMLSource =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    return true;
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    // In editor.js
+    CancelHTMLSource();
+  }
+};
+
+var nsConvertToTable =
+{
+  isCommandEnabled: function(aCommand, dummy)
+  {
+    if (IsDocumentEditable() && IsEditingRenderedHTML())
+    {
+      var selection;
+      try {
+        selection = GetCurrentEditor().selection;
+      } catch (e) {}
+
+      if (selection && !selection.isCollapsed)
+      {
+        // Don't allow if table or cell is the selection
+        var element;
+        try {
+          element = GetCurrentEditor().getSelectedElement("");
+        } catch (e) {}
+        if (element)
+        {
+          var name = element.nodeName.toLowerCase();
+          if (name == "td" ||
+              name == "th" ||
+              name == "caption" ||
+              name == "table")
+            return false;
+        }
+
+        // Selection start and end must be in the same cell
+        //   in same cell or both are NOT in a cell
+        if ( GetParentTableCell(selection.focusNode) !=
+             GetParentTableCell(selection.anchorNode) )
+          return false
+      
+        return true;
+      }
+    }
+    return false;
+  },
+
+  getCommandStateParams: function(aCommand, aParams, aRefCon) {},
+  doCommandParams: function(aCommand, aParams, aRefCon) {},
+
+  doCommand: function(aCommand)
+  {
+    if (this.isCommandEnabled())
+    {
+      window.openDialog("chrome://editor/content/EdConvertToTable.xul","_blank", "chrome,close,titlebar,modal")
+    }
+    window.content.focus();
+  }
+};
+
new file mode 100644
--- /dev/null
+++ b/editor/ui/composer/content/EditorAllTags.css
@@ -0,0 +1,835 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* Styles to alter look of things in the Editor content window 
+ *  for the "All Tags Edit Mode" Every HTML tag shows up as an icon.
+*/
+
+/* For "userdefined" or "unknown" tags
+   (Note that "_" must be escaped)
+*/
+
+*:not(a):not(abbr):not(acronym):not(address):not(applet):not(area):not(b):not(base):not(basefont):not(bdo):not(bgsound):not(big):not(blink):not(blockquote):not(body):not(br):not(button):not(canvas):not(caption):not(center):not(cite):not(code):not(col):not(colgroup):not(dd):not(del):not(dfn):not(dir):not(div):not(dl):not(dt):not(em):not(embed):not(fieldset):not(font):not(form):not(frame):not(frameset):not(h1):not(h2):not(h3):not(h4):not(h5):not(h6):not(head):not(hr):not(html):not(i):not(iframe):not(image):not(img):not(input):not(ins):not(isindex):not(kbd):not(keygen):not(label):not(legend):not(li):not(link):not(listing):not(map):not(marquee):not(menu):not(meta):not(multicol):not(nobr):not(noembed):not(noframes):not(noscript):not(object):not(ol):not(optgroup):not(option):not(p):not(param):not(plaintext):not(pre):not(q):not(s):not(samp):not(script):not(select):not(server):not(small):not(sound):not(spacer):not(span):not(strike):not(strong):not(style):not(sub):not(sup):not(table):not(tbody):not(td):not(textarea):not(tfoot):not(th):not(thead):not(title):not(tr):not(tt):not(u):not(ul):not(var):not(wbr):not(xmp) {
+  display: inline;
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 16px; 
+  background-image: url(chrome://editor/content/images/tag-userdefined.gif);
+  background-repeat: no-repeat;
+  background-position: top left;
+}
+
+a:not([\_moz_anonclass]) {
+  min-height: 16px; margin-left: 2px; margin-top: 2px;
+  padding-left: 20px; 
+  background-image: url(chrome://editor/content/images/tag-a.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+abbr {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 35px; 
+  background-image: url(chrome://editor/content/images/tag-abr.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+
+acronym {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 57px; 
+  background-image: url(chrome://editor/content/images/tag-acr.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+address {
+  min-height: 44px; margin-top: 2px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-adr.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+applet {
+  min-height: 35px; margin-top: 2px;
+  padding-left: 47px; 
+  background-image: url(chrome://editor/content/images/tag-app.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+area {
+  min-height: 35px; margin-top: 2px;
+  padding-left: 39px; 
+  background-image: url(chrome://editor/content/images/tag-ara.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+b {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 20px; 
+  background-image: url(chrome://editor/content/images/tag-b.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+basefont {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 57px; 
+  background-image: url(chrome://editor/content/images/tag-bsf.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+bdo {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 31px; 
+  background-image: url(chrome://editor/content/images/tag-bdo.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+big {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 31px; 
+  background-image: url(chrome://editor/content/images/tag-big.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+blockquote {
+  min-height: 44px; margin-left: 2px; margin-top: 2px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-blq.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+body {
+  min-height: 36px; margin-left: 2px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-body.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+br {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 23px; 
+  background-image: url(chrome://editor/content/images/tag-br.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+button {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 57px; 
+  background-image: url(chrome://editor/content/images/tag-btn.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+caption {
+  min-height: 35px; margin-top: 2px;
+  padding-left: 55px; 
+  background-image: url(chrome://editor/content/images/tag-cpt.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+center {
+  min-height: 44px; margin-top: 2px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-ctr.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+cite {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 39px; 
+  background-image: url(chrome://editor/content/images/tag-cit.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+code {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 39px; 
+  background-image: url(chrome://editor/content/images/tag-cod.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+col {
+  min-height: 35px; margin-left: 2px;
+  padding-left: 31px; 
+  background-image: url(chrome://editor/content/images/tag-col.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+colgroup {
+  min-height: 35px; margin-left: 2px;
+  padding-left: 51px; 
+  background-image: url(chrome://editor/content/images/tag-clg.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+dd {
+  min-height: 35px; margin-top: 2px;
+  padding-left: 23px; 
+  background-image: url(chrome://editor/content/images/tag-dd.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+del {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 31px; 
+  background-image: url(chrome://editor/content/images/tag-del.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+dfn {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 31px; 
+  background-image: url(chrome://editor/content/images/tag-dfn.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+dir {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 31px; 
+  background-image: url(chrome://editor/content/images/tag-dir.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+div {
+  min-height: 24px; margin-top: 2px;
+  /* TEMPORARY TO COMPENSATE FOR BUG */
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-div.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+input div {
+  min-height: 0px; margin-left: 0px; margin-top: 0px;
+  padding-left: 0px; 
+  background-image: none;
+}
+
+dl {
+  min-height: 20px; margin-top: 2px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-dl.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+dt {
+  min-height: 35px; margin-top: 2px;
+  padding-left: 23px; 
+  background-image: url(chrome://editor/content/images/tag-dt.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+em {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 23px; 
+  background-image: url(chrome://editor/content/images/tag-em.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+fieldset {
+  min-height: 44px; margin-top: 2px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-fld.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+font {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 39px; 
+  background-image: url(chrome://editor/content/images/tag-fnt.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+form {
+  min-height: 36px; margin-top: 2px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-for.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+frame {
+  min-height: 40px; margin-left: 2px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-frm.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+frameset {
+  min-height: 44px; margin-left: 2px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-fst.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+h1 {
+  min-height: 20px; margin-top: 2px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-h1.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+h2 {
+  min-height: 20px; margin-top: 2px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-h2.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+h3 {
+  min-height: 20px; margin-top: 2px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-h3.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+h4 {
+  min-height: 20px; margin-top: 2px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-h4.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+h5 {
+  min-height: 20px; margin-top: 2px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-h5.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+h6 {
+  min-height: 20px; margin-top: 2px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-h6.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+hr {
+  min-height: 20px; margin-top: 2px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-hr.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+i {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 20px; 
+  background-image: url(chrome://editor/content/images/tag-i.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+iframe {
+  min-height: 35px; margin-left: 2px;
+  padding-left: 47px; 
+  background-image: url(chrome://editor/content/images/tag-ifr.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+img:not([\_moz_anonclass]) {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 31px; 
+  background-image: url(chrome://editor/content/images/tag-img.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+input {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 39px; 
+  background-image: url(chrome://editor/content/images/tag-inp.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+ins {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 31px; 
+  background-image: url(chrome://editor/content/images/tag-ins.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+isindex {
+  min-height: 40px; margin-left: 2px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-isx.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+kbd {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 31px; 
+  background-image: url(chrome://editor/content/images/tag-kbd.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+label {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 39px; 
+  background-image: url(chrome://editor/content/images/tag-lbl.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+legend {
+  min-height: 35px; margin-top: 2px;
+  padding-left: 49px; 
+  background-image: url(chrome://editor/content/images/tag-lgn.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+li {
+  min-height: 35px; margin-top: 2px;
+  padding-left: 23px; 
+  background-image: url(chrome://editor/content/images/tag-li.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+listing {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 57px; 
+  background-image: url(chrome://editor/content/images/tag-lst.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+map {
+  min-height: 35px; margin-left: 2px;
+  padding-left: 31px; 
+  background-image: url(chrome://editor/content/images/tag-map.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+menu {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 39px; 
+  background-image: url(chrome://editor/content/images/tag-men.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+nobr {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 39px; 
+  background-image: url(chrome://editor/content/images/tag-nbr.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+noframes {
+  min-height: 44px; margin-left: 2px; margin-top: 2px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-nfr.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+noscript {
+  min-height: 44px; margin-left: 2px; margin-top: 2px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-nsc.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+object {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 49px; 
+  background-image: url(chrome://editor/content/images/tag-obj.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+ol {
+  min-height: 38px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-ol.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+optgroup {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 51px; 
+  background-image: url(chrome://editor/content/images/tag-opg.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+option {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 47px; 
+  background-image: url(chrome://editor/content/images/tag-opt.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+p {
+  min-height: 38px; margin-top: 2px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-p.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+param {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 43px; 
+  background-image: url(chrome://editor/content/images/tag-prm.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+plaintext {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 57px; 
+  background-image: url(chrome://editor/content/images/tag-pln.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+pre {
+  min-height: 24px; margin-top: 2px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-pre.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+q {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 20px; 
+  background-image: url(chrome://editor/content/images/tag-q.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+s {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 20px; 
+  background-image: url(chrome://editor/content/images/tag-s.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+samp {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 39px; 
+  background-image: url(chrome://editor/content/images/tag-smp.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+script {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 45px; 
+  background-image: url(chrome://editor/content/images/tag-scr.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+select {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 47px; 
+  background-image: url(chrome://editor/content/images/tag-slc.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+small {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 41px; 
+  background-image: url(chrome://editor/content/images/tag-sml.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+span:not([\_moz_anonclass]) {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  /* TEMPORARY TO COMPENSATE FOR BUG */
+  padding-left: 39px; 
+  background-image: url(chrome://editor/content/images/tag-spn.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+strike {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 45px; 
+  background-image: url(chrome://editor/content/images/tag-stk.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+strong {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 51px; 
+  background-image: url(chrome://editor/content/images/tag-stn.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+sub {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 31px; 
+  background-image: url(chrome://editor/content/images/tag-sub.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+sup {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 31px; 
+  background-image: url(chrome://editor/content/images/tag-sup.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+/* The background image technique is not working for 
+   some table elements. Trying the "before" strategy
+*/
+
+table {
+  min-height: 40px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-tbl.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+tbody {
+  min-height: 42px; margin-left: 2px; margin-top: 1px;
+  padding-left: 17px; 
+  content: url(chrome://editor/content/images/tag-tbd.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+td {
+  min-height: 22px; margin-left: 2px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-td.gif);
+
+  background-repeat: no-repeat;
+  background-position: top left;
+}
+
+textarea {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 59px; 
+  background-image: url(chrome://editor/content/images/tag-txt.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+tfoot {
+  min-height: 42px; margin-left: 2px; margin-top: 1px;
+  padding-left: 17px; 
+  content: url(chrome://editor/content/images/tag-tft.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+th {
+  min-height: 22px; margin-left: 2px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-th.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+thead {
+  min-height: 42px; margin-left: 2px; margin-top: 1px;
+  padding-left: 17px; 
+  content: url(chrome://editor/content/images/tag-thd.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+tr {
+  min-height: 22px; margin-left: 2px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-tr.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+tt {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 23px; 
+  background-image: url(chrome://editor/content/images/tag-tt.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+u {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 23px; 
+  background-image: url(chrome://editor/content/images/tag-u.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+ul {
+  min-height: 20px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-ul.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+var {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 31px; 
+  background-image: url(chrome://editor/content/images/tag-var.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+xmp {
+  min-height: 35px; margin-left: 2px; margin-top: 2px;
+  padding-left: 31px; 
+  background-image: url(chrome://editor/content/images/tag-xmp.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+
+/* These are tags that we DON'T want to show icons for.
+   We have images for them in case we want to utilize them
+   for some other purpose than the "All Tags" editor mode
+
+html {
+  min-height: 36px; margin-left: 2px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-html.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+head {
+  min-height: 36px; margin-left: 2px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-hed.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+These are tags that are ONLY allowed as children of HEAD:
+
+title {
+  min-height: 40px; margin-left: 2px; margin-top: 2px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-ttl.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+base {
+  min-height: 36px; margin-left: 2px; margin-top: 2px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-bas.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+style {
+  min-height: 40px; margin-left: 2px; margin-top: 2px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-stl.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+meta {
+  min-height: 36px; margin-left: 2px; margin-top: 2px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-met.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+link {
+  min-height: 30px; margin-left: 2px; margin-top: 2px;
+  padding-left: 17px; 
+  background-image: url(chrome://editor/content/images/tag-lnk.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+*/
new file mode 100644
--- /dev/null
+++ b/editor/ui/composer/content/EditorContent.css
@@ -0,0 +1,96 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Daniel Glazman <glazman@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* Styles to alter look of things in the Editor content window 
+ *  for the "Normal Edit Mode" These settings will be removed
+ *  when we display in completely WYSIWYG "Edit Preview" mode
+ *  Anything that should never change, like cursors, should be 
+ *  place in EditorOverride.css, instead of here.
+*/
+
+@import url(chrome://communicator/skin/smileys.css);
+
+a[name] {
+  min-height: 17px; margin-left: 2px; margin-top: 2px;
+  padding-left: 20px; 
+  background-image: url(chrome://editor/content/images/tag-anchor.gif);
+  background-repeat: no-repeat; 
+  background-position: top left;
+}
+
+/* Force border display for empty cells 
+   and tables with 0 border
+*/
+table {
+  empty-cells: show;
+}
+
+/* give a red dotted border to tables and cells with no border
+   otherwise they are invisible
+*/
+table[empty-cells],
+  table[border="0"],
+  /* next two selectors on line below for the case where tbody is omitted */
+  table[border="0"] > tr > td, table[border="0"] > tr > th,
+  table[border="0"] > thead > tr > td, table[border="0"] > tbody > tr > td, table[border="0"] > tfoot > tr > td,
+  table[border="0"] > thead > tr > th, table[border="0"] > tbody > tr > th, table[border="0"] > tfoot > tr > th,
+  table:not([border]),
+  /* next two selectors on line below for the case where tbody is omitted */
+  table:not([border]) > tr > td, table:not([border]) > tr >  th,
+  table:not([border]) > thead > tr > td, table:not([border]) > tbody > tr > td, table:not([border]) > tfoot > tr > td,
+  table:not([border]) > thead > tr > th, table:not([border]) > tbody > tr > th, table:not([border]) > tfoot > tr > th
+{
+  border: 1px dotted red;
+}
+
+/* give a green dashed border to forms otherwise they are invisible
+*/
+form
+{
+  border: 2px dashed green;
+}
+/* give a green dotted border to labels otherwise they are invisible
+*/
+label
+{
+  border: 1px dotted green;
+}
+
+img {
+  -moz-force-broken-image-icon: 1;
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/composer/content/EditorContextMenu.js
@@ -0,0 +1,172 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Charles Manske (cmanske@netscape.com)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+function EditorFillContextMenu(event, contextMenuNode)
+{
+  if ( event.target != contextMenuNode )
+    return;
+
+  // Setup object property menuitem
+  var objectName = InitObjectPropertiesMenuitem("objectProperties_cm");
+  var isInLink = objectName == "href";
+
+  // Special case of an image inside a link
+  if (objectName == "img")
+  try {
+    isInLink = GetCurrentEditor().getElementOrParentByTagName("href", GetObjectForProperties());
+  } catch (e) {}
+
+  InitRemoveStylesMenuitems("removeStylesMenuitem_cm", "removeLinksMenuitem_cm", "removeNamedAnchorsMenuitem_cm");
+
+  var inCell = IsInTableCell();
+  // Set appropriate text for join cells command
+  InitJoinCellMenuitem("joinTableCells_cm");
+
+  // Update enable states for all table commands
+  goUpdateTableMenuItems(document.getElementById("composerTableMenuItems"));
+
+  // Loop through all children to hide disabled items
+  var children = contextMenuNode.childNodes;
+  if (children)
+  {
+    var count = children.length;
+    for (var i = 0; i < count; i++)
+      HideDisabledItem(children[i]);
+  }
+
+  // The above loop will always show all separators and the next two items
+  // Hide "Create Link" if in a link
+  ShowMenuItem("createLink_cm", !isInLink);
+
+  // Hide "Edit link in new Composer" unless in a link
+  ShowMenuItem("editLink_cm", isInLink);
+
+  // Remove separators if all items in immediate group above are hidden
+  // A bit complicated to account if multiple groups are completely hidden!
+  var haveUndo =
+    IsMenuItemShowing("menu_undo_cm") ||
+    IsMenuItemShowing("menu_redo_cm");
+
+  var haveEdit =
+    IsMenuItemShowing("menu_cut_cm")   ||
+    IsMenuItemShowing("menu_copy_cm")  ||
+    IsMenuItemShowing("menu_paste_cm") ||
+    IsMenuItemShowing("menu_pasteNoFormatting_cm") ||
+    IsMenuItemShowing("menu_delete_cm");
+
+  var haveStyle =
+    IsMenuItemShowing("removeStylesMenuitem_cm") ||
+    IsMenuItemShowing("createLink_cm") ||
+    IsMenuItemShowing("removeLinksMenuitem_cm") ||
+    IsMenuItemShowing("removeNamedAnchorsMenuitem_cm");
+
+  var haveProps =
+    IsMenuItemShowing("objectProperties_cm");
+
+  ShowMenuItem("undoredo-separator", haveUndo && haveEdit);
+
+  ShowMenuItem("edit-separator", haveEdit || haveUndo);
+
+  // Note: Item "menu_selectAll_cm" and
+  // following separator are ALWAYS enabled,
+  // so there will always be 1 separator here
+
+  var showStyleSep = haveStyle && (haveProps || inCell);
+  ShowMenuItem("styles-separator", showStyleSep);
+
+  var showPropSep = (haveProps && inCell);
+  ShowMenuItem("property-separator", showPropSep);
+
+  // Remove table submenus if not in table
+  ShowMenuItem("tableInsertMenu_cm",  inCell);
+  ShowMenuItem("tableSelectMenu_cm",  inCell);
+  ShowMenuItem("tableDeleteMenu_cm",  inCell);
+
+  // if we have a mispelled word, show spellchecker context
+  // menuitems as well as the usual context menu
+  InlineSpellCheckerUI.clearSuggestionsFromMenu();
+  InlineSpellCheckerUI.initFromEvent(document.popupRangeParent, document.popupRangeOffset);
+  var onMisspelling = InlineSpellCheckerUI.overMisspelling;
+  document.getElementById('spellCheckSuggestionsSeparator').hidden = !onMisspelling;
+  document.getElementById('spellCheckAddToDictionary').hidden = !onMisspelling;
+  document.getElementById('spellCheckIgnoreWord').hidden = !onMisspelling;
+  var separator = document.getElementById('spellCheckAddSep');
+  separator.hidden = !onMisspelling;
+  document.getElementById('spellCheckNoSuggestions').hidden = !onMisspelling ||
+      InlineSpellCheckerUI.addSuggestionsToMenu(contextMenuNode, separator, 5);
+}
+
+function IsItemOrCommandEnabled( item )
+{
+  var command = item.getAttribute("command");
+  if (command) {
+    // If possible, query the command controller directly
+    var controller = document.commandDispatcher.getControllerForCommand(command);
+    if (controller)
+      return controller.isCommandEnabled(command);
+  }
+
+  // Fall back on the inefficient observed disabled attribute
+  return item.getAttribute("disabled") != "true";
+}
+
+function HideDisabledItem( item )
+{
+  item.hidden = !IsItemOrCommandEnabled(item);
+}
+
+function ShowMenuItem(id, showItem)
+{
+  var item = document.getElementById(id);
+  if (item && !showItem)
+  {
+    item.hidden = true;
+  }
+  // else HideDisabledItem showed the item anyway
+}
+
+function IsMenuItemShowing(menuID)
+{
+  var item = document.getElementById(menuID);
+  if (item)
+    return !item.hidden;
+
+  return false;
+}
+
new file mode 100644
--- /dev/null
+++ b/editor/ui/composer/content/EditorContextMenuOverlay.xul
@@ -0,0 +1,164 @@
+<?xml version="1.0"?> 
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 2000
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -   Daniel Glazman (glazman@netscape.com)
+   -   Charles Manske (cmanske@netscape.com)
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!DOCTYPE overlay SYSTEM "chrome://editor/locale/editorOverlay.dtd">
+
+<overlay id="ComposerContextMenuOverlay"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+<script type="application/x-javascript" src="chrome://editor/content/EditorContextMenu.js"/>
+<script type="application/x-javascript" src="chrome://editor/content/StructBarContextMenu.js"/>
+<script type="application/x-javascript" src="chrome://global/content/inlineSpellCheckUI.js"/>
+
+<popupset id="editorContentContextSet">
+ <popup id="editorContentContext"   
+   onpopupshowing="EditorFillContextMenu(event, this);"> 
+    <menuitem id="spellCheckNoSuggestions" label="&spellCheckNoSuggestions.label;" disabled="true"/>
+    <menuseparator id="spellCheckAddSep"/>
+    <menuitem id="spellCheckAddToDictionary"
+              label="&spellCheckAddToDictionary.label;"
+              accesskey="&spellCheckAddToDictionary.accesskey;"
+              oncommand="InlineSpellCheckerUI.addToDictionary();"/>
+    <menuitem id="spellCheckIgnoreWord"
+              label="&spellCheckIgnoreWord.label;"
+              accesskey="&spellCheckIgnoreWord.accesskey;"
+              oncommand="InlineSpellCheckerUI.ignoreWord();"/>
+    <menuseparator id="spellCheckSuggestionsSeparator"/>
+
+    <menuitem id="menu_undo_cm"   label="&undoCmd.label;" accesskey="&undo.accesskey;" command="cmd_undo"/>
+    <menuitem id="menu_redo_cm"   label="&redoCmd.label;" accesskey="&redo.accesskey;" command="cmd_redo"/>
+    <menuseparator id="undoredo-separator"/>
+    
+    <menuitem id="menu_cut_cm"    label="&cutCmd.label;"    accesskey="&cut.accesskey;" command="cmd_cut"/>
+    <menuitem id="menu_copy_cm"   label="&copyCmd.label;"   accesskey="&copy.accesskey;" command="cmd_copy"/>
+    <menuitem id="menu_paste_cm"  label="&pasteCmd.label;"  accesskey="&paste.accesskey;" command="cmd_paste"/>
+    <menuitem id="menu_pasteNoFormatting_cm" command="cmd_pasteNoFormatting"/>
+    <menuitem id="menu_delete_cm" label="&deleteCmd.label;" accesskey="&delete.accesskey;" command="cmd_delete"/>
+    <menuseparator id="edit-separator"/>
+    <menuitem id="menu_selectAll_cm" label="&selectAllCmd.label;" accesskey="&selectall.accesskey;" command="cmd_selectAll"/>
+    <menuseparator id="selectAll-separator"/>
+    
+    <!-- label and accesskey set at runtime from strings -->
+    <menuitem id="removeStylesMenuitem_cm"
+          observes="cmd_removeStyles"/>
+    <menuitem id="createLink_cm" label="&createLinkCmd.label;" accesskey="&createlink.accesskey;" command="cmd_link"/>
+    <!-- label and accesskey set at runtime from strings -->
+    <menuitem id="removeLinksMenuitem_cm" observes="cmd_removeLinks"/>
+    <menuitem id="removeNamedAnchorsMenuitem_cm"  label="&formatRemoveNamedAnchors.label;"   
+          accesskey="&formatRemoveNamedAnchors.accesskey;"
+          observes="cmd_removeNamedAnchors"/>
+    <menuseparator id="styles-separator"/>
+
+    <!-- label and accesskey are set in InitObjectProperties -->
+    <menuitem id="objectProperties_cm" observes="cmd_objectProperties"/>
+    <menuitem id="editLink_cm" label="&editLinkCmd.label;" accesskey="&editlink.accesskey;" command="cmd_editLink"/>
+    <menuseparator id="property-separator"/>
+
+    <!-- Can't get submenus to load from a shared overlay -->
+    <menu id="tableInsertMenu_cm" label="&tableInsertMenu2.label;" accesskey="&tableinsertmenu.accesskey;">
+      <menupopup>
+        <menuitem label="&insertTableCmd.label;"    accesskey="&tabletable.accesskey;"        observes="cmd_InsertTable"/>
+        <menuseparator />
+        <menuitem label="&tableRowAbove.label;"     accesskey="&tablerow.accesskey;"          observes="cmd_InsertRowAbove"/>
+        <menuitem label="&tableRowBelow.label;"     accesskey="&tablerowbelow.accesskey;"     observes="cmd_InsertRowBelow"/>
+        <menuseparator />
+        <menuitem label="&tableColumnBefore.label;" accesskey="&tablecolumn.accesskey;"       observes="cmd_InsertColumnBefore"/>
+        <menuitem label="&tableColumnAfter.label;"  accesskey="&tablecolumnafter.accesskey;"  observes="cmd_InsertColumnAfter"/>
+        <menuseparator />
+        <menuitem label="&tableCellBefore.label;"   accesskey="&tablecell.accesskey;"         observes="cmd_InsertCellBefore"/>
+        <menuitem label="&tableCellAfter.label;"    accesskey="&tablecellafter.accesskey;"    observes="cmd_InsertCellAfter"/>
+      </menupopup>
+    </menu>
+    <menu id="tableSelectMenu_cm" label="&tableSelectMenu2.label;" accesskey="&tableselectmenu.accesskey;">
+      <menupopup>
+        <menuitem id="menu_SelectTable_cm"    label="&tableTable.label;"    accesskey="&tabletable.accesskey;"    observes="cmd_SelectTable"    />
+        <menuitem id="menu_SelectRow_cm"      label="&tableRow.label;"      accesskey="&tablerow.accesskey;"      observes="cmd_SelectRow"      />
+        <menuitem id="menu_SelectColumn_cm"   label="&tableColumn.label;"   accesskey="&tablecolumn.accesskey;"   observes="cmd_SelectColumn"   />
+        <menuitem id="menu_SelectCell_cm"     label="&tableCell.label;"     accesskey="&tablecell.accesskey;"     observes="cmd_SelectCell"     />
+        <menuitem id="menu_SelectAllCells_cm" label="&tableAllCells.label;" accesskey="&tableallcells.accesskey;" observes="cmd_SelectAllCells" />
+      </menupopup>
+    </menu>
+    <menu id="tableDeleteMenu_cm" label="&tableDeleteMenu2.label;" accesskey="&tabledeletemenu.accesskey;">
+      <menupopup>
+        <menuitem id="menu_DeleteTable_cm"        label="&tableTable.label;"        accesskey="&tabletable.accesskey;"          observes="cmd_DeleteTable"/>
+        <menuitem id="menu_DeleteRow_cm"          label="&tableRows.label;"         accesskey="&tablerow.accesskey;"            observes="cmd_DeleteRow"/>
+        <menuitem id="menu_DeleteColumn_cm"       label="&tableColumns.label;"      accesskey="&tablecolumn.accesskey;"         observes="cmd_DeleteColumn"/>
+        <menuitem id="menu_DeleteCell_cm"         label="&tableCells.label;"        accesskey="&tablecell.accesskey;"           observes="cmd_DeleteCell"/>
+        <menuitem id="menu_DeleteCellContents_cm" label="&tableCellContents.label;" accesskey="&tablecellcontents.accesskey;"   observes="cmd_DeleteCellContents"/>
+      </menupopup>
+    </menu>
+    <!-- menu label is set in InitTableMenu -->
+    <menuitem id="joinTableCells_cm"   label="&tableJoinCells.label;" accesskey="&tablejoincells.accesskey;" observes="cmd_JoinTableCells"/>
+    <menuitem id="splitTableCell_cm"   label="&tableSplitCell.label;" accesskey="&tablesplitcell.accesskey;" observes="cmd_SplitTableCell"/>
+    <menuitem id="tableOrCellColor_cm" label="&tableOrCellColor.label;" accesskey="&tableOrCellColor.accesskey;" observes="cmd_TableOrCellColor"/>
+ </popup>
+
+ <popup id="editorSourceContext">
+   <menuitem label="&undoCmd.label;"      accesskey="&undo.accesskey;"      command="cmd_undo"/>
+   <menuitem label="&redoCmd.label;"      accesskey="&redo.accesskey;"      command="cmd_redo"/>
+   <menuseparator/>
+   <menuitem label="&cutCmd.label;"       accesskey="&cut.accesskey;"       command="cmd_cut"/>
+   <menuitem label="&copyCmd.label;"      accesskey="&copy.accesskey;"      command="cmd_copy"/>
+   <menuitem label="&pasteCmd.label;"     accesskey="&paste.accesskey;"     command="cmd_paste"/>
+   <menuitem label="&deleteCmd.label;"    accesskey="&delete.accesskey;"    command="cmd_delete"/>
+   <menuseparator/>
+   <menuitem label="&selectAllCmd.label;" accesskey="&selectall.accesskey;" command="cmd_selectAll"/>
+ </popup>
+
+ <popup id="structToolbarContext">
+   <menuitem id="structSelect"     label="&structSelect.label;"
+                                   accesskey="&structSelect.accesskey;"
+                                   oncommand="StructSelectTag()"/>
+   <menuseparator/>
+   <menuitem id="structRemoveTag"  label="&structRemoveTag.label;"
+                                   accesskey="&structRemoveTag.accesskey;"
+                                   oncommand="StructRemoveTag()"/>
+   <menuitem id="structChangeTag"  label="&structChangeTag.label;"
+                                   accesskey="&structChangeTag.accesskey;"
+                                   oncommand="StructChangeTag()"/>
+   <menuseparator/>
+   <menuitem id="advancedPropsTag" label="&advancedPropertiesCmd.label;"
+                                   accesskey="&advancedproperties.accesskey;"
+                                   oncommand="OpenAdvancedProperties()"/>
+ </popup>
+
+</popupset>
+
+</overlay>
new file mode 100644
--- /dev/null
+++ b/editor/ui/composer/content/EditorParagraphMarks.css
@@ -0,0 +1,49 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* This adds the standard paragraph symbol 
+ *  after paragraphs (block container tags)
+*/
+
+p:after,br:after,
+h1:after,h2:after,h3:after,h4:after,h5:after,h6:after,
+address:after,blockquote:after,listing:after,
+plaintext:after, xmp:after, pre:after,
+li:after,dt:after,dd:after
+{
+  content: "\B6 ";
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/composer/content/StructBarContextMenu.js
@@ -0,0 +1,212 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *    Daniel Glazman (glazman@netscape.com), original author
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var gContextMenuNode;
+var gContextMenuFiringDocumentElement;
+
+function InitStructBarContextMenu(button, docElement)
+{
+  gContextMenuFiringDocumentElement = docElement;
+  gContextMenuNode = button;
+
+  var tag = docElement.nodeName.toLowerCase();
+
+  var structRemoveTag = document.getElementById("structRemoveTag");
+  var enableRemove;
+
+  switch (tag) {
+    case "body":
+    case "tbody":
+    case "thead":
+    case "tfoot":
+    case "col":
+    case "colgroup":
+    case "tr":
+    case "th":
+    case "td":
+    case "caption":
+      enableRemove = false;
+      break;
+    default:
+      enableRemove = true;
+      break;
+  }
+  SetElementEnabled(structRemoveTag, enableRemove);
+
+  var structChangeTag = document.getElementById("structChangeTag");
+  SetElementEnabled(structChangeTag, (tag != "body"));
+}
+
+function TableCellFilter(node)
+{
+  switch (node.nodeName.toLowerCase())
+    {
+    case "td":
+    case "th":
+    case "caption":
+      return NodeFilter.FILTER_ACCEPT;
+      break;
+    default:
+      return NodeFilter.FILTER_SKIP;
+      break;
+    }
+  return NodeFilter.FILTER_SKIP;
+}
+
+function StructRemoveTag()
+{
+  var editor = GetCurrentEditor();
+  if (!editor) return;
+
+  var element = gContextMenuFiringDocumentElement;
+  var offset = 0;
+  var childNodes = element.parentNode.childNodes;
+
+  while (childNodes[offset] != element) {
+    ++offset;
+  }
+
+  editor.beginTransaction();
+
+  try {
+
+    var tag = element.nodeName.toLowerCase();
+    if (tag != "table") {
+      MoveChildNodesAfterElement(editor, element, element, offset);
+    }
+    else {
+
+      var nodeIterator = document.createTreeWalker(element,
+                                                   NodeFilter.SHOW_ELEMENT,
+                                                   TableCellFilter,
+                                                   true);
+      var node = nodeIterator.lastChild();
+      while (node) {
+        MoveChildNodesAfterElement(editor, node, element, offset);
+        node = nodeIterator.previousSibling();
+      }
+
+    }
+    editor.deleteNode(element);
+  }
+  catch (e) {};
+
+  editor.endTransaction();
+}
+
+function MoveChildNodesAfterElement(editor, element, targetElement, targetOffset)
+{
+  var childNodes = element.childNodes;
+  var childNodesLength = childNodes.length;
+  var i;
+  for (i = childNodesLength - 1; i >= 0; i--) {
+    var clone = childNodes.item(i).cloneNode(true);
+    editor.insertNode(clone, targetElement.parentNode, targetOffset + 1);
+  }
+}
+
+function StructChangeTag()
+{
+  var textbox = document.createElementNS(XUL_NS, "textbox");
+  textbox.setAttribute("value", gContextMenuNode.getAttribute("value"));
+  textbox.setAttribute("width", gContextMenuNode.boxObject.width);
+  textbox.className = "struct-textbox";
+
+  gContextMenuNode.parentNode.replaceChild(textbox, gContextMenuNode);
+
+  textbox.addEventListener("keypress", OnKeyPress, false);
+  textbox.addEventListener("blur", ResetStructToolbar, true);
+
+  textbox.select();
+}
+
+function StructSelectTag()
+{
+  SelectFocusNodeAncestor(gContextMenuFiringDocumentElement);
+}
+
+function OpenAdvancedProperties()
+{
+  doAdvancedProperties(gContextMenuFiringDocumentElement);
+}
+
+function OnKeyPress(event)
+{
+  var editor = GetCurrentEditor();
+
+  var keyCode = event.keyCode;
+  if (keyCode == 13) {
+    var newTag = event.target.value;
+
+    var element = gContextMenuFiringDocumentElement;
+
+    var offset = 0;
+    var childNodes = element.parentNode.childNodes;
+    while (childNodes.item(offset) != element) {
+      offset++;
+    }
+
+    editor.beginTransaction();
+
+    try {
+      var newElt = editor.document.createElement(newTag);
+      if (newElt) {
+        childNodes = element.childNodes;
+        var childNodesLength = childNodes.length;
+        var i;
+        for (i = 0; i < childNodesLength; i++) {
+          var clone = childNodes.item(i).cloneNode(true);
+          newElt.appendChild(clone);
+        }
+        editor.insertNode(newElt, element.parentNode, offset+1);
+        editor.deleteNode(element);
+        editor.selectElement(newElt);
+
+        window.content.focus();
+      }
+    }
+    catch (e) {}
+
+    editor.endTransaction();
+
+  }
+  else if (keyCode == 27) {
+    // if the user hits Escape, we discard the changes
+    window.content.focus();
+  }
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/composer/content/composerOverlay.xul
@@ -0,0 +1,48 @@
+<?xml version="1.0"?> 
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -   Charles Manske (cmanske@netscape.com)
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<overlay id="composerOverlay"
+         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+  <!-- Items in the Edit menu used only by Composer app -->
+  <menupopup id="edEditMenuPopup">
+    <menuitem id="menu_publishSettings" insertafter="menu_prefsSep"  observes="cmd_publishSettings"/>
+  </menupopup>
+
+</overlay>    
new file mode 100644
--- /dev/null
+++ b/editor/ui/composer/content/editor.js
@@ -0,0 +1,3468 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Sammy Ford (sford@swbell.net)
+ *   Dan Haddix (dan6992@hotmail.com)
+ *   John Ratke (jratke@owc.net)
+ *   Ryan Cassin (rcassin@supernova.org)
+ *   Daniel Glazman (glazman@netscape.com)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* Main Composer window UI control */
+
+var gComposerWindowControllerID = 0;
+var prefAuthorString = "";
+
+const kDisplayModeNormal = 0;
+const kDisplayModeAllTags = 1;
+const kDisplayModeSource = 2;
+const kDisplayModePreview = 3;
+const kDisplayModeMenuIDs = ["viewNormalMode", "viewAllTagsMode", "viewSourceMode", "viewPreviewMode"];
+const kDisplayModeTabIDS = ["NormalModeButton", "TagModeButton", "SourceModeButton", "PreviewModeButton"];
+const kNormalStyleSheet = "chrome://editor/content/EditorContent.css";
+const kAllTagsStyleSheet = "chrome://editor/content/EditorAllTags.css";
+const kParagraphMarksStyleSheet = "chrome://editor/content/EditorParagraphMarks.css";
+const kContentEditableStyleSheet = "resource://gre/res/contenteditable.css";
+
+const kTextMimeType = "text/plain";
+const kHTMLMimeType = "text/html";
+
+const nsIWebNavigation = Components.interfaces.nsIWebNavigation;
+
+var gPreviousNonSourceDisplayMode = 1;
+var gEditorDisplayMode = -1;
+var gDocWasModified = false;  // Check if clean document, if clean then unload when user "Opens"
+var gContentWindow = 0;
+var gSourceContentWindow = 0;
+var gSourceTextEditor = null;
+var gContentWindowDeck;
+var gFormatToolbar;
+var gFormatToolbarHidden = false;
+var gViewFormatToolbar;
+var gColorObj = { LastTextColor:"", LastBackgroundColor:"", LastHighlightColor:"",
+                  Type:"", SelectedType:"", NoDefault:false, Cancel:false,
+                  HighlightColor:"", BackgroundColor:"", PageColor:"",
+                  TextColor:"", TableColor:"", CellColor:""
+                };
+var gDefaultTextColor = "";
+var gDefaultBackgroundColor = "";
+var gCSSPrefListener;
+var gEditorToolbarPrefListener;
+var gReturnInParagraphPrefListener;
+var gPrefs;
+var gLocalFonts = null;
+
+var gLastFocusNode = null;
+var gLastFocusNodeWasSelected = false;
+
+// These must be kept in synch with the XUL <options> lists
+var gFontSizeNames = ["xx-small","x-small","small","medium","large","x-large","xx-large"];
+
+const nsIFilePicker = Components.interfaces.nsIFilePicker;
+
+const kEditorToolbarPrefs = "editor.toolbars.showbutton.";
+const kUseCssPref         = "editor.use_css";
+const kCRInParagraphsPref = "editor.CR_creates_new_p";
+
+function ShowHideToolbarSeparators(toolbar) {
+  var childNodes = toolbar.childNodes;
+  var separator = null;
+  var hideSeparator = true;
+  for (var i = 0; childNodes[i].localName != "spacer"; i++) {
+    if (childNodes[i].localName == "toolbarseparator") {
+      if (separator)
+        separator.hidden = true;
+      separator = childNodes[i];
+    } else if (!childNodes[i].hidden) {
+      if (separator)
+        separator.hidden = hideSeparator;
+      separator = null;
+      hideSeparator = false;
+    }
+  }
+}
+
+function ShowHideToolbarButtons()
+{
+  var array = gPrefs.getChildList(kEditorToolbarPrefs, {});
+  for (var i in array) {
+    var prefName = array[i];
+    var id = prefName.substr(kEditorToolbarPrefs.length) + "Button";
+    var button = document.getElementById(id);
+    if (button)
+      button.hidden = !gPrefs.getBoolPref(prefName);
+  }
+  ShowHideToolbarSeparators(document.getElementById("EditToolbar"));
+  ShowHideToolbarSeparators(document.getElementById("FormatToolbar"));
+}
+  
+function nsPrefListener(prefName)
+{
+  this.startup(prefName);
+}
+
+// implements nsIObserver
+nsPrefListener.prototype =
+{
+  domain: "",
+  startup: function(prefName)
+  {
+    this.domain = prefName;
+    try {
+      var pbi = pref.QueryInterface(Components.interfaces.nsIPrefBranch2);
+      pbi.addObserver(this.domain, this, false);
+    } catch(ex) {
+      dump("Failed to observe prefs: " + ex + "\n");
+    }
+  },
+  shutdown: function()
+  {
+    try {
+      var pbi = pref.QueryInterface(Components.interfaces.nsIPrefBranch2);
+      pbi.removeObserver(this.domain, this);
+    } catch(ex) {
+      dump("Failed to remove pref observers: " + ex + "\n");
+    }
+  },
+  observe: function(subject, topic, prefName)
+  {
+    if (!IsHTMLEditor())
+      return;
+    // verify that we're changing a button pref
+    if (topic != "nsPref:changed") return;
+    
+    var editor = GetCurrentEditor();
+    if (prefName == kUseCssPref)
+    {
+      var cmd = document.getElementById("cmd_highlight");
+      if (cmd) {
+        var useCSS = gPrefs.getBoolPref(prefName);
+
+        if (useCSS && editor) {
+          var mixedObj = {};
+          var state = editor.getHighlightColorState(mixedObj);
+          cmd.setAttribute("state", state);
+          cmd.collapsed = false;
+        }      
+        else {
+          cmd.setAttribute("state", "transparent");
+          cmd.collapsed = true;
+        }
+
+        if (editor)
+          editor.isCSSEnabled = useCSS;
+      }
+    }
+    else if (prefName.substr(0, kEditorToolbarPrefs.length) == kEditorToolbarPrefs)
+    {
+      var id = prefName.substr(kEditorToolbarPrefs.length) + "Button";
+      var button = document.getElementById(id);
+      if (button) {
+        button.hidden = !gPrefs.getBoolPref(prefName);
+        ShowHideToolbarSeparators(button.parentNode);
+      }
+    }
+    else if (editor && (prefName == kCRInParagraphsPref))
+      editor.returnInParagraphCreatesNewParagraph = gPrefs.getBoolPref(prefName);
+  }
+}
+
+function AfterHighlightColorChange()
+{
+  if (!IsHTMLEditor())
+    return;
+
+  var button = document.getElementById("cmd_highlight");
+  if (button) {
+    var mixedObj = {};
+    try {
+      var state = GetCurrentEditor().getHighlightColorState(mixedObj);
+      button.setAttribute("state", state);
+      onHighlightColorChange();
+    } catch (e) {}
+  }      
+}
+
+function EditorOnLoad()
+{
+    // See if argument was passed.
+    if ( window.arguments && window.arguments[0] ) {
+        // Opened via window.openDialog with URL as argument.
+        // Put argument where EditorStartup expects it.
+        document.getElementById( "args" ).setAttribute( "value", window.arguments[0] );
+    }
+
+    // get default character set if provided
+    if ("arguments" in window && window.arguments.length > 1 && window.arguments[1]) {
+      if (window.arguments[1].indexOf("charset=") != -1) {
+        var arrayArgComponents = window.arguments[1].split("=");
+        if (arrayArgComponents) {
+          // Put argument where EditorStartup expects it.
+          document.getElementById( "args" ).setAttribute("charset", arrayArgComponents[1]);
+        }
+      }
+    }
+
+    window.tryToClose = EditorCanClose;
+
+    // Continue with normal startup.
+    EditorStartup();
+
+    // Initialize our source text <editor>
+    try {
+      gSourceContentWindow = document.getElementById("content-source");
+      gSourceContentWindow.makeEditable("text", false);
+      gSourceTextEditor = gSourceContentWindow.getEditor(gSourceContentWindow.contentWindow);
+      gSourceTextEditor.QueryInterface(Components.interfaces.nsIPlaintextEditor);
+      gSourceTextEditor.enableUndo(false);
+      gSourceTextEditor.rootElement.style.fontFamily = "-moz-fixed";
+      gSourceTextEditor.rootElement.style.whiteSpace = "pre";
+      gSourceTextEditor.rootElement.style.margin = 0;
+      var controller = Components.classes["@mozilla.org/embedcomp/base-command-controller;1"]
+                                 .createInstance(Components.interfaces.nsIControllerContext);
+      controller.init(null);
+      controller.setCommandContext(gSourceContentWindow);
+      gSourceContentWindow.contentWindow.controllers.insertControllerAt(0, controller);
+      var commandTable = controller.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+                                   .getInterface(Components.interfaces.nsIControllerCommandTable);
+      commandTable.registerCommand("cmd_find",        nsFindCommand);
+      commandTable.registerCommand("cmd_findNext",    nsFindAgainCommand);
+      commandTable.registerCommand("cmd_findPrev",    nsFindAgainCommand);
+    } catch (e) { dump("makeEditable failed: "+e+"\n"); }
+}
+
+const gSourceTextListener =
+{
+  NotifyDocumentCreated: function NotifyDocumentCreated() {},
+  NotifyDocumentWillBeDestroyed: function NotifyDocumentWillBeDestroyed() {},
+  NotifyDocumentStateChanged: function NotifyDocumentStateChanged(isChanged)
+  {
+    window.updateCommands("save");
+  }
+};
+
+const gSourceTextObserver =
+{
+  observe: function observe(aSubject, aTopic, aData)
+  {
+    // we currently only use this to update undo
+    window.updateCommands("undo");
+  }
+};
+
+function TextEditorOnLoad()
+{
+    // See if argument was passed.
+    if ( window.arguments && window.arguments[0] ) {
+        // Opened via window.openDialog with URL as argument.
+        // Put argument where EditorStartup expects it.
+        document.getElementById( "args" ).setAttribute( "value", window.arguments[0] );
+    }
+    // Continue with normal startup.
+    EditorStartup();
+}
+
+// This should be called by all editor users when they close their window
+//  or other similar "done with editor" actions, like recycling a Mail Composer window.
+function EditorCleanup()
+{
+  SwitchInsertCharToAnotherEditorOrClose();
+}
+
+var DocumentReloadListener =
+{
+  NotifyDocumentCreated: function() {},
+  NotifyDocumentWillBeDestroyed: function() {},
+
+  NotifyDocumentStateChanged:function( isNowDirty )
+  {
+    var editor = GetCurrentEditor();
+    try {
+      // unregister the listener to prevent multiple callbacks
+      editor.removeDocumentStateListener( DocumentReloadListener );
+
+      var charset = editor.documentCharacterSet;
+
+      // update the META charset with the current presentation charset
+      editor.documentCharacterSet = charset;
+
+    } catch (e) {}
+  }
+};
+
+function addEditorClickEventListener()
+{
+  try {
+    var bodyelement = GetBodyElement();
+    if (bodyelement)
+      bodyelement.addEventListener("click", EditorClick, false);
+  } catch (e) {}
+}
+
+// implements nsIObserver
+var gEditorDocumentObserver =
+{ 
+  observe: function(aSubject, aTopic, aData)
+  {
+    // Should we allow this even if NOT the focused editor?
+    var commandManager = GetCurrentCommandManager();
+    if (commandManager != aSubject)
+      return;
+
+    var editor = GetCurrentEditor();
+    switch(aTopic)
+    {
+      case "obs_documentCreated":
+        // Just for convenience
+        gContentWindow = window.content;
+
+        // Get state to see if document creation succeeded
+        var params = newCommandParams();
+        if (!params)
+          return;
+
+        try {
+          commandManager.getCommandState(aTopic, gContentWindow, params);
+          var errorStringId = 0;
+          var editorStatus = params.getLongValue("state_data");
+          if (!editor && editorStatus == nsIEditingSession.eEditorOK)
+          {
+            dump("\n ****** NO EDITOR BUT NO EDITOR ERROR REPORTED ******* \n\n");
+            editorStatus = nsIEditingSession.eEditorErrorUnknown;
+          }
+
+          switch (editorStatus)
+          {
+            case nsIEditingSession.eEditorErrorCantEditFramesets:
+              errorStringId = "CantEditFramesetMsg";
+              break;
+            case nsIEditingSession.eEditorErrorCantEditMimeType:
+              errorStringId = "CantEditMimeTypeMsg";
+              break;
+            case nsIEditingSession.eEditorErrorUnknown:
+              errorStringId = "CantEditDocumentMsg";
+              break;
+            // Note that for "eEditorErrorFileNotFound, 
+            // network code popped up an alert dialog, so we don't need to
+          }
+          if (errorStringId)
+            AlertWithTitle("", GetString(errorStringId));
+        } catch(e) { dump("EXCEPTION GETTING obs_documentCreated state "+e+"\n"); }
+
+        // We have a bad editor -- nsIEditingSession will rebuild an editor
+        //   with a blank page, so simply abort here
+        if (editorStatus)
+          return; 
+
+        if (!("InsertCharWindow" in window))
+          window.InsertCharWindow = null;
+
+        try {
+          editor.QueryInterface(nsIEditorStyleSheets);
+
+          //  and extra styles for showing anchors, table borders, smileys, etc
+          editor.addOverrideStyleSheet(kNormalStyleSheet);
+
+          // remove contenteditable stylesheets if they were applied by the
+          // editingSession
+          editor.removeOverrideStyleSheet(kContentEditableStyleSheet);
+        } catch (e) {}
+
+        // Things for just the Web Composer application
+        if (IsWebComposer())
+        {
+          InlineSpellCheckerUI.init(editor);
+          document.getElementById('menu_inlinespellcheck').setAttribute('disabled', !InlineSpellCheckerUI.canSpellCheck);
+
+          editor.returnInParagraphCreatesNewParagraph = gPrefs.getBoolPref(kCRInParagraphsPref);
+
+          // Set focus to content window if not a mail composer
+          // Race conditions prevent us from setting focus here
+          //   when loading a url into blank window
+          setTimeout(SetFocusOnStartup, 0);
+
+          // Call EditorSetDefaultPrefsAndDoctype first so it gets the default author before initing toolbars
+          EditorSetDefaultPrefsAndDoctype();
+
+          // We may load a text document into an html editor,
+          //   so be sure editortype is set correctly
+          // XXX We really should use the "real" plaintext editor for this!
+          if (editor.contentsMIMEType == "text/plain")
+          {
+            try {
+              GetCurrentEditorElement().editortype = "text";
+            } catch (e) { dump (e)+"\n"; }
+
+            // Hide or disable UI not used for plaintext editing
+            HideItem("FormatToolbar");
+            HideItem("EditModeToolbar");
+            HideItem("formatMenu");
+            HideItem("tableMenu");
+            HideItem("menu_validate");
+            HideItem("sep_validate");
+            HideItem("previewButton");
+            HideItem("imageButton");
+            HideItem("linkButton");
+            HideItem("namedAnchorButton");
+            HideItem("hlineButton");
+            HideItem("tableButton");
+
+            HideItem("fileExportToText");
+            HideItem("previewInBrowser");
+
+/* XXX When paste actually converts formatted rich text to pretty formatted plain text
+       and pasteNoFormatting is fixed to paste the text without formatting (what paste
+       currently does), then this item shouldn't be hidden: */
+            HideItem("menu_pasteNoFormatting"); 
+
+            HideItem("cmd_viewFormatToolbar");
+            HideItem("cmd_viewEditModeToolbar");
+
+            HideItem("viewSep1");
+            HideItem("viewNormalMode");
+            HideItem("viewAllTagsMode");
+            HideItem("viewSourceMode");
+            HideItem("viewPreviewMode");
+
+            HideItem("structSpacer");
+
+            // Hide everything in "Insert" except for "Symbols"
+            var menuPopup = document.getElementById("insertMenuPopup");
+            if (menuPopup)
+            {
+              var children = menuPopup.childNodes;
+              for (var i=0; i < children.length; i++) 
+              {
+                var item = children.item(i);
+                if (item.id != "insertChars")
+                  item.hidden = true;
+              }
+            }
+          }
+    
+          // Set window title
+          UpdateWindowTitle();
+
+          // We must wait until document is created to get proper Url
+          // (Windows may load with local file paths)
+          SetSaveAndPublishUI(GetDocumentUrl());
+
+          // Start in "Normal" edit mode
+          SetDisplayMode(kDisplayModeNormal);
+        }
+
+        // Add mouse click watcher if right type of editor
+        if (IsHTMLEditor())
+        {
+          addEditorClickEventListener();
+
+          // Force color widgets to update
+          onFontColorChange();
+          onBackgroundColorChange();
+        }
+        break;
+
+      case "cmd_setDocumentModified":
+        window.updateCommands("save");
+        break;
+
+      case "obs_documentWillBeDestroyed":
+        dump("obs_documentWillBeDestroyed notification\n");
+        break;
+
+      case "obs_documentLocationChanged":
+        // Ignore this when editor doesn't exist,
+        //   which happens once when page load starts
+        if (editor)
+          try {
+            editor.updateBaseURL();
+          } catch(e) { dump (e); }
+        break;
+
+      case "cmd_bold":
+        // Update all style items
+        // cmd_bold is a proxy; see EditorSharedStartup (above) for details
+        window.updateCommands("style");
+        window.updateCommands("undo");
+        break;
+    }
+  }
+}
+
+function SetFocusOnStartup()
+{
+  gContentWindow.focus();
+}
+
+function EditorStartup()
+{
+  var ds = GetCurrentEditorElement().docShell;
+  ds.useErrorPages = false;
+  var root = ds.QueryInterface(Components.interfaces.nsIDocShellTreeItem).
+    rootTreeItem.QueryInterface(Components.interfaces.nsIDocShell);
+
+  root.QueryInterface(Components.interfaces.nsIDocShell).appType =
+    Components.interfaces.nsIDocShell.APP_TYPE_EDITOR;
+
+  var is_HTMLEditor = IsHTMLEditor();
+  if (is_HTMLEditor)
+  {
+    // XUL elements we use when switching from normal editor to edit source
+    gContentWindowDeck = document.getElementById("ContentWindowDeck");
+    gFormatToolbar = document.getElementById("FormatToolbar");
+    gViewFormatToolbar = document.getElementById("viewFormatToolbar");
+  }
+
+  // set up our global prefs object
+  GetPrefsService();
+
+  // Startup also used by other editor users, such as Message Composer
+  EditorSharedStartup();
+
+  // Commands specific to the Composer Application window,
+  //  (i.e., not embedded editors)
+  //  such as file-related commands, HTML Source editing, Edit Modes...
+  SetupComposerWindowCommands();
+
+  ShowHideToolbarButtons();
+  gEditorToolbarPrefListener = new nsPrefListener(kEditorToolbarPrefs);
+
+  gCSSPrefListener = new nsPrefListener(kUseCssPref);
+  gReturnInParagraphPrefListener = new nsPrefListener(kCRInParagraphsPref);
+
+  // hide Highlight button if we are in an HTML editor with CSS mode off
+  // and tell the editor if a CR in a paragraph creates a new paragraph
+  var cmd = document.getElementById("cmd_highlight");
+  if (cmd) {
+    var useCSS = gPrefs.getBoolPref(kUseCssPref);
+    if (!useCSS && is_HTMLEditor) {
+      cmd.collapsed = true;
+    }
+  }
+
+  // Get url for editor content and load it.
+  // the editor gets instantiated by the edittingSession when the URL has finished loading.
+  var url = document.getElementById("args").getAttribute("value");
+  try {
+    var charset = document.getElementById("args").getAttribute("charset");
+    var contentViewer = GetCurrentEditorElement().docShell.contentViewer;
+    contentViewer.QueryInterface(Components.interfaces.nsIMarkupDocumentViewer);
+    contentViewer.defaultCharacterSet = charset;
+    contentViewer.forceCharacterSet = charset;
+  } catch (e) {}
+  EditorLoadUrl(url);
+}
+
+function EditorLoadUrl(url)
+{
+  try {
+    if (url)
+      GetCurrentEditorElement().webNavigation.loadURI(url, // uri string
+             nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE,     // load flags
+             null,                                         // referrer
+             null,                                         // post-data stream
+             null);
+  } catch (e) { dump(" EditorLoadUrl failed: "+e+"\n"); }
+}
+
+// This should be called by all Composer types
+function EditorSharedStartup()
+{
+  // Just for convenience
+  gContentWindow = window.content;
+
+  // Set up the mime type and register the commands.
+  if (IsHTMLEditor())
+    SetupHTMLEditorCommands();
+  else
+    SetupTextEditorCommands();
+
+  // add observer to be called when document is really done loading 
+  // and is modified
+  // Note: We're really screwed if we fail to install this observer!
+  try {
+    var commandManager = GetCurrentCommandManager();
+    commandManager.addCommandObserver(gEditorDocumentObserver, "obs_documentCreated");
+    commandManager.addCommandObserver(gEditorDocumentObserver, "cmd_setDocumentModified");
+    commandManager.addCommandObserver(gEditorDocumentObserver, "obs_documentWillBeDestroyed");
+    commandManager.addCommandObserver(gEditorDocumentObserver, "obs_documentLocationChanged");
+
+    // Until nsIControllerCommandGroup-based code is implemented,
+    //  we will observe just the bold command to trigger update of
+    //  all toolbar style items
+    commandManager.addCommandObserver(gEditorDocumentObserver, "cmd_bold");
+  } catch (e) { dump(e); }
+
+  var isMac = (GetOS() == gMac);
+
+  // Set platform-specific hints for how to select cells
+  // Mac uses "Cmd", all others use "Ctrl"
+  var tableKey = GetString(isMac ? "XulKeyMac" : "TableSelectKey");
+  var dragStr = tableKey+GetString("Drag");
+  var clickStr = tableKey+GetString("Click");
+
+  var delStr = GetString(isMac ? "Clear" : "Del");
+
+  SafeSetAttribute("menu_SelectCell", "acceltext", clickStr);
+  SafeSetAttribute("menu_SelectRow", "acceltext", dragStr);
+  SafeSetAttribute("menu_SelectColumn", "acceltext", dragStr);
+  SafeSetAttribute("menu_SelectAllCells", "acceltext", dragStr);
+  // And add "Del" or "Clear"
+  SafeSetAttribute("menu_DeleteCellContents", "acceltext", delStr);
+
+  // Set text for indent, outdent keybinding
+
+  // hide UI that we don't have components for
+  RemoveInapplicableUIElements();
+
+  gPrefs = GetPrefs();
+
+  // Use browser colors as initial values for editor's default colors
+  var BrowserColors = GetDefaultBrowserColors();
+  if (BrowserColors)
+  {
+    gDefaultTextColor = BrowserColors.TextColor;
+    gDefaultBackgroundColor = BrowserColors.BackgroundColor;
+  }
+
+  // For new window, no default last-picked colors
+  gColorObj.LastTextColor = "";
+  gColorObj.LastBackgroundColor = "";
+  gColorObj.LastHighlightColor = "";
+}
+
+// This method is only called by Message composer when recycling a compose window
+function EditorResetFontAndColorAttributes()
+{
+  try {  
+    var editor = GetCurrentEditor();
+    editor.rebuildDocumentFromSource("");
+    // Because the selection is now collapsed, the following line
+    // clears the typing state to discontinue all inline styles
+    editor.removeAllInlineProperties();
+    document.getElementById("cmd_fontFace").setAttribute("state", "");
+    gColorObj.LastTextColor = "";
+    gColorObj.LastBackgroundColor = "";
+    gColorObj.LastHighlightColor = "";
+    document.getElementById("cmd_fontColor").setAttribute("state", "");
+    document.getElementById("cmd_backgroundColor").setAttribute("state", "");
+    UpdateDefaultColors();
+  } catch (e) {}
+}
+
+function EditorShutdown()
+{
+  gEditorToolbarPrefListener.shutdown();
+  gCSSPrefListener.shutdown();
+  gReturnInParagraphPrefListener.shutdown();
+
+  try {
+    var commandManager = GetCurrentCommandManager();
+    commandManager.removeCommandObserver(gEditorDocumentObserver, "obs_documentCreated");
+    commandManager.removeCommandObserver(gEditorDocumentObserver, "obs_documentWillBeDestroyed");
+    commandManager.removeCommandObserver(gEditorDocumentObserver, "obs_documentLocationChanged");
+  } catch (e) { dump (e); }   
+}
+
+function SafeSetAttribute(nodeID, attributeName, attributeValue)
+{
+    var theNode = document.getElementById(nodeID);
+    if (theNode)
+        theNode.setAttribute(attributeName, attributeValue);
+}
+
+function DocumentHasBeenSaved()
+{
+  var fileurl = "";
+  try {
+    fileurl = GetDocumentUrl();
+  } catch (e) {
+    return false;
+  }
+
+  if (!fileurl || IsUrlAboutBlank(fileurl))
+    return false;
+
+  // We have a file URL already
+  return true;
+}
+
+function CheckAndSaveDocument(command, allowDontSave)
+{
+  var document;
+  try {
+    // if we don't have an editor or an document, bail
+    var editor = GetCurrentEditor();
+    document = editor.document;
+    if (!document)
+      return true;
+  } catch (e) { return true; }
+
+  if (!IsDocumentModified() && !IsHTMLSourceChanged())
+    return true;
+
+  // call window.focus, since we need to pop up a dialog
+  // and therefore need to be visible (to prevent user confusion)
+  top.document.commandDispatcher.focusedWindow.focus();  
+
+  var scheme = GetScheme(GetDocumentUrl());
+  var doPublish = (scheme && scheme != "file");
+
+  var strID;
+  switch (command)
+  {
+    case "cmd_close":
+      strID = "BeforeClosing";
+      break;
+    case "cmd_preview":
+      strID = "BeforePreview";
+      break;
+    case "cmd_editSendPage":
+      strID = "SendPageReason";
+      break;
+    case "cmd_validate":
+      strID = "BeforeValidate";
+      break;
+  }
+    
+  var reasonToSave = strID ? GetString(strID) : "";
+
+  var title = document.title;
+  if (!title)
+    title = GetString("untitled");
+
+  var dialogTitle = GetString(doPublish ? "PublishPage" : "SaveDocument");
+  var dialogMsg = GetString(doPublish ? "PublishPrompt" : "SaveFilePrompt");
+  dialogMsg = (dialogMsg.replace(/%title%/,title)).replace(/%reason%/,reasonToSave);
+
+  var promptService = GetPromptService();
+  if (!promptService)
+    return false;
+
+  var result = {value:0};
+  var promptFlags = promptService.BUTTON_TITLE_CANCEL * promptService.BUTTON_POS_1;
+  var button1Title = null;
+  var button3Title = null;
+
+  if (doPublish)
+  {
+    promptFlags += promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_0;
+    button1Title = GetString("Publish");
+    button3Title = GetString("DontPublish");    
+  }
+  else
+  {
+    promptFlags += promptService.BUTTON_TITLE_SAVE * promptService.BUTTON_POS_0;
+  }
+
+  // If allowing "Don't..." button, add that
+  if (allowDontSave)
+    promptFlags += doPublish ?
+        (promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_2)
+        : (promptService.BUTTON_TITLE_DONT_SAVE * promptService.BUTTON_POS_2);
+  
+  result = promptService.confirmEx(window, dialogTitle, dialogMsg, promptFlags,
+                          button1Title, null, button3Title, null, {value:0});
+
+  if (result == 0)
+  {
+    // Save, but first finish HTML source mode
+    if (IsHTMLSourceChanged()) {
+      try {
+        FinishHTMLSource();
+      } catch (e) { return false;}
+    }
+
+    if (doPublish)
+    {
+      // We save the command the user wanted to do in a global
+      // and return as if user canceled because publishing is asynchronous
+      // This command will be fired when publishing finishes
+      gCommandAfterPublishing = command;
+      goDoCommand("cmd_publish");
+      return false;
+    }
+
+    // Save to local disk
+    var contentsMIMEType;
+    if (IsHTMLEditor())
+      contentsMIMEType = kHTMLMimeType;
+    else
+      contentsMIMEType = kTextMimeType;
+    var success = SaveDocument(false, false, contentsMIMEType);
+    return success;
+  }
+
+  if (result == 2) // "Don't Save"
+    return true;
+
+  // Default or result == 1 (Cancel)
+  return false;
+}
+
+// --------------------------- File menu ---------------------------
+
+// Check for changes to document and allow saving before closing
+// This is hooked up to the OS's window close widget (e.g., "X" for Windows)
+function EditorCanClose()
+{
+  // Returns FALSE only if user cancels save action
+
+  // "true" means allow "Don't Save" button
+  var canClose = CheckAndSaveDocument("cmd_close", true);
+
+  // This is our only hook into closing via the "X" in the caption
+  //   or "Quit" (or other paths?)
+  //   so we must shift association to another
+  //   editor or close any non-modal windows now
+  if (canClose && "InsertCharWindow" in window && window.InsertCharWindow)
+    SwitchInsertCharToAnotherEditorOrClose();
+
+  return canClose;
+}
+
+// --------------------------- View menu ---------------------------
+
+function EditorSetDocumentCharacterSet(aCharset)
+{
+  try {
+    var editor = GetCurrentEditor();
+    editor.documentCharacterSet = aCharset;
+    var docUrl = GetDocumentUrl();
+    if( !IsUrlAboutBlank(docUrl))
+    {
+      // reloading the document will reverse any changes to the META charset, 
+      // we need to put them back in, which is achieved by a dedicated listener
+      editor.addDocumentStateListener( DocumentReloadListener );
+      EditorLoadUrl(docUrl);
+    }
+  } catch (e) {}
+}
+
+// ------------------------------------------------------------------
+function updateCharsetPopupMenu(menuPopup)
+{
+  if (IsDocumentModified() && !IsDocumentEmpty())
+  {
+    for (var i = 0; i < menuPopup.childNodes.length; i++)
+    {
+      var menuItem = menuPopup.childNodes[i];
+      menuItem.setAttribute('disabled', 'true');
+    }
+  }
+}
+
+// --------------------------- Text style ---------------------------
+
+function onParagraphFormatChange(paraMenuList, commandID)
+{
+  if (!paraMenuList)
+    return;
+
+  var commandNode = document.getElementById(commandID);
+  var state = commandNode.getAttribute("state");
+
+  // force match with "normal"
+  if (state == "body")
+    state = "";
+
+  if (state == "mixed")
+  {
+    //Selection is the "mixed" ( > 1 style) state
+    paraMenuList.selectedItem = null;
+    paraMenuList.setAttribute("label",GetString('Mixed'));
+  }
+  else
+  {
+    var menuPopup = document.getElementById("ParagraphPopup");
+    var menuItems = menuPopup.childNodes;
+    for (var i=0; i < menuItems.length; i++)
+    {
+      var menuItem = menuItems.item(i);
+      if ("value" in menuItem && menuItem.value == state)
+      {
+        paraMenuList.selectedItem = menuItem;
+        break;
+      }
+    }
+  }
+}
+
+function onFontFaceChange(fontFaceMenuList, commandID)
+{
+  var commandNode = document.getElementById(commandID);
+  var state = commandNode.getAttribute("state");
+
+  if (state == "mixed")
+  {
+    //Selection is the "mixed" ( > 1 style) state
+    fontFaceMenuList.selectedItem = null;
+    fontFaceMenuList.setAttribute("label",GetString('Mixed'));
+  }
+  else
+  {
+    var menuPopup = document.getElementById("FontFacePopup");
+    var menuItems = menuPopup.childNodes;
+    for (var i=0; i < menuItems.length; i++)
+    {
+      var menuItem = menuItems.item(i);
+      if (menuItem.getAttribute("label") && ("value" in menuItem && menuItem.value.toLowerCase() == state.toLowerCase()))
+      {
+        fontFaceMenuList.selectedItem = menuItem;
+        break;
+      }
+    }
+  }
+}
+
+function EditorSelectFontSize()
+{
+  var select = document.getElementById("FontSizeSelect");
+  if (select)
+  {
+    if (select.selectedIndex == -1)
+      return;
+
+    EditorSetFontSize(gFontSizeNames[select.selectedIndex]);
+  }
+}
+
+function onFontSizeChange(fontSizeMenulist, commandID)
+{
+  // If we don't match anything, set to "0 (normal)"
+  var newIndex = 2;
+  var size = fontSizeMenulist.getAttribute("size");
+  if ( size == "mixed")
+  {
+    // No single type selected
+    newIndex = -1;
+  }
+  else
+  {
+    for (var i = 0; i < gFontSizeNames.length; i++)
+    {
+      if( gFontSizeNames[i] == size )
+      {
+        newIndex = i;
+        break;
+      }
+    }
+  }
+  if (fontSizeMenulist.selectedIndex != newIndex)
+    fontSizeMenulist.selectedIndex = newIndex;
+}
+
+function EditorSetFontSize(size)
+{
+  if( size == "0" || size == "normal" ||
+      size == "medium" )
+  {
+    EditorRemoveTextProperty("font", "size");
+    // Also remove big and small,
+    //  else it will seem like size isn't changing correctly
+    EditorRemoveTextProperty("small", "");
+    EditorRemoveTextProperty("big", "");
+  } else {
+    // Temp: convert from new CSS size strings to old HTML size strings
+    switch (size)
+    {
+      case "xx-small":
+      case "x-small":
+        size = "-2";
+        break;
+      case "small":
+        size = "-1";
+        break;
+      case "large":
+        size = "+1";
+        break;
+      case "x-large":
+        size = "+2";
+        break;
+      case "xx-large":
+        size = "+3";
+        break;
+    }
+    EditorSetTextProperty("font", "size", size);
+  }
+  gContentWindow.focus();
+}
+
+function initFontFaceMenu(menuPopup)
+{
+  initLocalFontFaceMenu(menuPopup);
+
+  if (menuPopup)
+  {
+    var children = menuPopup.childNodes;
+    if (!children) return;
+
+    var firstHas = { value: false };
+    var anyHas = { value: false };
+    var allHas = { value: false };
+
+    // we need to set or clear the checkmark for each menu item since the selection
+    // may be in a new location from where it was when the menu was previously opened
+
+    // Fixed width (second menu item) is special case: old TT ("teletype") attribute
+    EditorGetTextProperty("tt", "", "", firstHas, anyHas, allHas);
+    children[1].setAttribute("checked", allHas.value);
+
+    if (!anyHas.value)
+      EditorGetTextProperty("font", "face", "", firstHas, anyHas, allHas);
+
+    children[0].setAttribute("checked", !anyHas.value);
+
+    // Skip over default, TT, and separator
+    for (var i = 3; i < children.length; i++)
+    {
+      var menuItem = children[i];
+      var faceType = menuItem.getAttribute("value");
+
+      if (faceType)
+      {
+        EditorGetTextProperty("font", "face", faceType, firstHas, anyHas, allHas);
+
+        // Check the menuitem only if all of selection has the face
+        if (allHas.value)
+        {
+          menuItem.setAttribute("checked", "true");
+          break;
+        }
+
+        // in case none match, make sure we've cleared the checkmark
+        menuItem.removeAttribute("checked");
+      }
+    }
+  }
+}
+
+const kFixedFontFaceMenuItems = 7; // number of fixed font face menuitems
+
+function initLocalFontFaceMenu(menuPopup)
+{
+  if (!gLocalFonts)
+  {
+    // Build list of all local fonts once per editor
+    try 
+    {
+      var enumerator = Components.classes["@mozilla.org/gfx/fontenumerator;1"]
+                                 .getService(Components.interfaces.nsIFontEnumerator);
+      var localFontCount = { value: 0 }
+      gLocalFonts = enumerator.EnumerateAllFonts(localFontCount);
+    }
+    catch(e) { }
+  }
+  
+  var useRadioMenuitems = (menuPopup.parentNode.localName == "menu"); // don't do this for menulists  
+  if (menuPopup.childNodes.length == kFixedFontFaceMenuItems) 
+  {
+    if (gLocalFonts.length == 0) {
+      menuPopup.childNodes[kFixedFontFaceMenuItems - 1].hidden = true;
+    }
+    for (var i = 0; i < gLocalFonts.length; ++i)
+    {
+      if (gLocalFonts[i] != "")
+      {
+        var itemNode = document.createElementNS(XUL_NS, "menuitem");
+        itemNode.setAttribute("label", gLocalFonts[i]);
+        itemNode.setAttribute("value", gLocalFonts[i]);
+        if (useRadioMenuitems) {
+          itemNode.setAttribute("type", "radio");
+          itemNode.setAttribute("name", "2");
+          itemNode.setAttribute("observes", "cmd_renderedHTMLEnabler");
+        }
+        menuPopup.appendChild(itemNode);
+      }
+    }
+  }
+}
+ 
+
+function initFontSizeMenu(menuPopup)
+{
+  if (menuPopup)
+  {
+    var children = menuPopup.childNodes;
+    if (!children) return;
+
+    var firstHas = { value: false };
+    var anyHas = { value: false };
+    var allHas = { value: false };
+
+    var sizeWasFound = false;
+
+    // we need to set or clear the checkmark for each menu item since the selection
+    // may be in a new location from where it was when the menu was previously opened
+
+    // First 2 items add <small> and <big> tags
+    // While it would be better to show the number of levels,
+    //  at least this tells user if either of them are set
+    var menuItem = children[0];
+    if (menuItem)
+    {
+      EditorGetTextProperty("small", "", "", firstHas, anyHas, allHas);
+      menuItem.setAttribute("checked", allHas.value);
+      sizeWasFound = anyHas.value;
+    }
+
+    menuItem = children[1];
+    if (menuItem)
+    {
+      EditorGetTextProperty("big", "", "", firstHas, anyHas, allHas);
+      menuItem.setAttribute("checked", allHas.value);
+      sizeWasFound |= anyHas.value;
+    }
+
+    // Fixed size items start after menu separator
+    var menuIndex = 3;
+    // Index of the medium (default) item
+    var mediumIndex = 5;
+
+    // Scan through all supported "font size" attribute values
+    for (var i = -2; i <= 3; i++)
+    {
+      menuItem = children[menuIndex];
+
+      // Skip over medium since it'll be set below.
+      // If font size=0 is actually set, we'll toggle it off below if
+      // we enter this loop in this case.
+      if (menuItem && (i != 0))
+      {
+        var sizeString = (i <= 0) ? String(i) : ("+" + String(i));
+        EditorGetTextProperty("font", "size", sizeString, firstHas, anyHas, allHas);
+        // Check the item only if all of selection has the size...
+        menuItem.setAttribute("checked", allHas.value);
+        // ...but remember if ANY of of selection had size set
+        sizeWasFound |= anyHas.value;
+      }
+      menuIndex++;
+    }
+
+    // if no size was found, then check default (medium)
+    // note that no item is checked in the case of "mixed" selection
+    children[mediumIndex].setAttribute("checked", !sizeWasFound);
+  }
+}
+
+function onHighlightColorChange()
+{
+  var commandNode = document.getElementById("cmd_highlight");
+  if (commandNode)
+  {
+    var color = commandNode.getAttribute("state");
+    var button = document.getElementById("HighlightColorButton");
+    if (button)
+    {
+      // No color set - get color set on page or other defaults
+      if (!color)
+        color = "transparent" ;
+
+      button.setAttribute("style", "background-color:"+color+" !important");
+    }
+  }
+}
+
+function onFontColorChange()
+{
+  var commandNode = document.getElementById("cmd_fontColor");
+  if (commandNode)
+  {
+    var color = commandNode.getAttribute("state");
+    var button = document.getElementById("TextColorButton");
+    if (button)
+    {
+      // No color set - get color set on page or other defaults
+      if (!color)
+        color = gDefaultTextColor;
+      button.setAttribute("style", "background-color:"+color);
+    }
+  }
+}
+
+function onBackgroundColorChange()
+{
+  var commandNode = document.getElementById("cmd_backgroundColor");
+  if (commandNode)
+  {
+    var color = commandNode.getAttribute("state");
+    var button = document.getElementById("BackgroundColorButton");
+    if (button)
+    {
+      if (!color)
+        color = gDefaultBackgroundColor;
+
+      button.setAttribute("style", "background-color:"+color);
+    }
+  }
+}
+
+// Call this when user changes text and/or background colors of the page
+function UpdateDefaultColors()
+{
+  var BrowserColors = GetDefaultBrowserColors();
+  var bodyelement = GetBodyElement();
+  var defTextColor = gDefaultTextColor;
+  var defBackColor = gDefaultBackgroundColor;
+
+  if (bodyelement)
+  {
+    var color = bodyelement.getAttribute("text");
+    if (color)
+      gDefaultTextColor = color;
+    else if (BrowserColors)
+      gDefaultTextColor = BrowserColors.TextColor;
+
+    color = bodyelement.getAttribute("bgcolor");
+    if (color)
+      gDefaultBackgroundColor = color;
+    else if (BrowserColors)
+      gDefaultBackgroundColor = BrowserColors.BackgroundColor;
+  }
+
+  // Trigger update on toolbar
+  if (defTextColor != gDefaultTextColor)
+  {
+    goUpdateCommandState("cmd_fontColor");
+    onFontColorChange();
+  }
+  if (defBackColor != gDefaultBackgroundColor)
+  {
+    goUpdateCommandState("cmd_backgroundColor");
+    onBackgroundColorChange();
+  }
+}
+
+function GetBackgroundElementWithColor()
+{
+  var editor = GetCurrentTableEditor();
+  if (!editor)
+    return null;
+
+  gColorObj.Type = "";
+  gColorObj.PageColor = "";
+  gColorObj.TableColor = "";
+  gColorObj.CellColor = "";
+  gColorObj.BackgroundColor = "";
+  gColorObj.SelectedType = "";
+
+  var tagNameObj = { value: "" };
+  var element;
+  try {
+    element = editor.getSelectedOrParentTableElement(tagNameObj, {value:0});
+  }
+  catch(e) {}
+
+  if (element && tagNameObj && tagNameObj.value)
+  {
+    gColorObj.BackgroundColor = GetHTMLOrCSSStyleValue(element, "bgcolor", "background-color");
+    gColorObj.BackgroundColor = ConvertRGBColorIntoHEXColor(gColorObj.BackgroundColor);
+    if (tagNameObj.value.toLowerCase() == "td")
+    {
+      gColorObj.Type = "Cell";
+      gColorObj.CellColor = gColorObj.BackgroundColor;
+
+      // Get any color that might be on parent table
+      var table = GetParentTable(element);
+      gColorObj.TableColor = GetHTMLOrCSSStyleValue(table, "bgcolor", "background-color");
+      gColorObj.TableColor = ConvertRGBColorIntoHEXColor(gColorObj.TableColor);
+    }
+    else
+    {
+      gColorObj.Type = "Table";
+      gColorObj.TableColor = gColorObj.BackgroundColor;
+    }
+    gColorObj.SelectedType = gColorObj.Type;
+  }
+  else
+  {
+    var IsCSSPrefChecked = gPrefs.getBoolPref(kUseCssPref);
+    if (IsCSSPrefChecked && IsHTMLEditor())
+    {
+      var selection = editor.selection;
+      if (selection)
+      {
+        element = selection.focusNode;
+        while (!editor.nodeIsBlock(element))
+          element = element.parentNode;
+      }
+      else
+      {
+        element = GetBodyElement();
+      }
+    }
+    else
+    {
+      element = GetBodyElement();
+    }
+    if (element)
+    {
+      gColorObj.Type = "Page";
+      gColorObj.BackgroundColor = GetHTMLOrCSSStyleValue(element, "bgcolor", "background-color");
+      if (gColorObj.BackgroundColor == "")
+      {
+        gColorObj.BackgroundColor = "transparent";
+      }
+      else
+      {
+        gColorObj.BackgroundColor = ConvertRGBColorIntoHEXColor(gColorObj.BackgroundColor);
+      }
+      gColorObj.PageColor = gColorObj.BackgroundColor;
+    }
+  }
+  return element;
+}
+
+function SetSmiley(smileyText)
+{
+  try {
+    GetCurrentEditor().insertText(smileyText);
+    gContentWindow.focus();
+  }
+  catch(e) {}
+}
+
+function EditorSelectColor(colorType, mouseEvent)
+{
+  var editor = GetCurrentEditor();
+  if (!editor || !gColorObj)
+    return;
+
+  // Shift + mouse click automatically applies last color, if available
+  var useLastColor = mouseEvent ? ( mouseEvent.button == 0 && mouseEvent.shiftKey ) : false;
+  var element;
+  var table;
+  var currentColor = "";
+  var commandNode;
+
+  if (!colorType)
+    colorType = "";
+
+  if (colorType == "Text")
+  {
+    gColorObj.Type = colorType;
+
+    // Get color from command node state
+    commandNode = document.getElementById("cmd_fontColor");
+    currentColor = commandNode.getAttribute("state");
+    currentColor = ConvertRGBColorIntoHEXColor(currentColor);
+    gColorObj.TextColor = currentColor;
+
+    if (useLastColor && gColorObj.LastTextColor )
+      gColorObj.TextColor = gColorObj.LastTextColor;
+    else
+      useLastColor = false;
+  }
+  else if (colorType == "Highlight")
+  {
+    gColorObj.Type = colorType;
+
+    // Get color from command node state
+    commandNode = document.getElementById("cmd_highlight");
+    currentColor = commandNode.getAttribute("state");
+    currentColor = ConvertRGBColorIntoHEXColor(currentColor);
+    gColorObj.HighlightColor = currentColor;
+
+    if (useLastColor && gColorObj.LastHighlightColor )
+      gColorObj.HighlightColor = gColorObj.LastHighlightColor;
+    else
+      useLastColor = false;
+  }
+  else
+  {
+    element = GetBackgroundElementWithColor();
+    if (!element)
+      return;
+
+    // Get the table if we found a cell
+    if (gColorObj.Type == "Table")
+      table = element;
+    else if (gColorObj.Type == "Cell")
+      table = GetParentTable(element);
+
+    // Save to avoid resetting if not necessary
+    currentColor = gColorObj.BackgroundColor;
+
+    if (colorType == "TableOrCell" || colorType == "Cell")
+    {
+      if (gColorObj.Type == "Cell")
+        gColorObj.Type = colorType;
+      else if (gColorObj.Type != "Table")
+        return;
+    }
+    else if (colorType == "Table" && gColorObj.Type == "Page")
+      return;
+
+    if (colorType == "" && gColorObj.Type == "Cell")
+    {
+      // Using empty string for requested type means
+      //  we can let user select cell or table
+      gColorObj.Type = "TableOrCell";
+    }
+
+    if (useLastColor && gColorObj.LastBackgroundColor )
+      gColorObj.BackgroundColor = gColorObj.LastBackgroundColor;
+    else
+      useLastColor = false;
+  }
+  // Save the type we are really requesting
+  colorType = gColorObj.Type;
+
+  if (!useLastColor)
+  {
+    // Avoid the JS warning
+    gColorObj.NoDefault = false;
+
+    // Launch the ColorPicker dialog
+    // TODO: Figure out how to position this under the color buttons on the toolbar
+    window.openDialog("chrome://editor/content/EdColorPicker.xul", "_blank", "chrome,close,titlebar,modal", "", gColorObj);
+
+    // User canceled the dialog
+    if (gColorObj.Cancel)
+      return;
+  }
+
+  if (gColorObj.Type == "Text")
+  {
+    if (currentColor != gColorObj.TextColor)
+    {
+      if (gColorObj.TextColor)
+        EditorSetTextProperty("font", "color", gColorObj.TextColor);
+      else
+        EditorRemoveTextProperty("font", "color");
+    }
+    // Update the command state (this will trigger color button update)
+    goUpdateCommandState("cmd_fontColor");
+  }
+  else if (gColorObj.Type == "Highlight")
+  {
+    if (currentColor != gColorObj.HighlightColor)
+    {
+      if (gColorObj.HighlightColor)
+        EditorSetTextProperty("font", "bgcolor", gColorObj.HighlightColor);
+      else
+        EditorRemoveTextProperty("font", "bgcolor");
+    }
+    // Update the command state (this will trigger color button update)
+    goUpdateCommandState("cmd_highlight");
+  }
+  else if (element)
+  {
+    if (gColorObj.Type == "Table")
+    {
+      // Set background on a table
+      // Note that we shouldn't trust "currentColor" because of "TableOrCell" behavior
+      if (table)
+      {
+        var bgcolor = table.getAttribute("bgcolor");
+        if (bgcolor != gColorObj.BackgroundColor)
+        try {
+          if (gColorObj.BackgroundColor)
+            editor.setAttributeOrEquivalent(table, "bgcolor", gColorObj.BackgroundColor, false);
+          else
+            editor.removeAttributeOrEquivalent(table, "bgcolor", false);
+        } catch (e) {}
+      }
+    }
+    else if (currentColor != gColorObj.BackgroundColor && IsHTMLEditor())
+    {
+      editor.beginTransaction();
+      try
+      {
+        editor.setBackgroundColor(gColorObj.BackgroundColor);
+
+        if (gColorObj.Type == "Page" && gColorObj.BackgroundColor)
+        {
+          // Set all page colors not explicitly set,
+          //  else you can end up with unreadable pages
+          //  because viewer's default colors may not be same as page author's
+          var bodyelement = GetBodyElement();
+          if (bodyelement)
+          {
+            var defColors = GetDefaultBrowserColors();
+            if (defColors)
+            {
+              if (!bodyelement.getAttribute("text"))
+                editor.setAttributeOrEquivalent(bodyelement, "text", defColors.TextColor, false);
+
+              // The following attributes have no individual CSS declaration counterparts
+              // Getting rid of them in favor of CSS implies CSS rules management
+              if (!bodyelement.getAttribute("link"))
+                editor.setAttribute(bodyelement, "link", defColors.LinkColor);
+
+              if (!bodyelement.getAttribute("alink"))
+                editor.setAttribute(bodyelement, "alink", defColors.ActiveLinkColor);
+
+              if (!bodyelement.getAttribute("vlink"))
+                editor.setAttribute(bodyelement, "vlink", defColors.VisitedLinkColor);
+            }
+          }
+        }
+      }
+      catch(e) {}
+
+      editor.endTransaction();
+    }
+
+    goUpdateCommandState("cmd_backgroundColor");
+  }
+  gContentWindow.focus();
+}
+
+function GetParentTable(element)
+{
+  var node = element;
+  while (node)
+  {
+    if (node.nodeName.toLowerCase() == "table")
+      return node;
+
+    node = node.parentNode;
+  }
+  return node;
+}
+
+function GetParentTableCell(element)
+{
+  var node = element;
+  while (node)
+  {
+    if (node.nodeName.toLowerCase() == "td" || node.nodeName.toLowerCase() == "th")
+      return node;
+
+    node = node.parentNode;
+  }
+  return node;
+}
+
+function EditorDblClick(event)
+{
+  // We check event.explicitOriginalTarget here because .target will never
+  // be a textnode (bug 193689)
+  if (event.explicitOriginalTarget)
+  {
+    // Only bring up properties if clicked on an element or selected link
+    var element;
+    try {
+      element = event.explicitOriginalTarget.QueryInterface(
+                    Components.interfaces.nsIDOMElement);
+    } catch (e) {}
+
+     //  We use "href" instead of "a" to not be fooled by named anchor
+    if (!element)
+      try {
+        element = GetCurrentEditor().getSelectedElement("href");
+      } catch (e) {}
+
+    if (element)
+    {
+      goDoCommand("cmd_objectProperties");  
+      event.preventDefault();
+    }
+  }
+}
+
+function EditorClick(event)
+{
+  if (!event)
+    return;
+
+  if (event.detail == 2)
+  {
+    EditorDblClick(event);
+    return;
+  }
+
+  // For Web Composer: In Show All Tags Mode,
+  // single click selects entire element,
+  //  except for body and table elements
+  if (IsWebComposer() && event.explicitOriginalTarget && IsHTMLEditor() &&
+      gEditorDisplayMode == kDisplayModeAllTags)
+  {
+    try
+    {
+      // We check event.explicitOriginalTarget here because .target will never
+      // be a textnode (bug 193689)
+      var element = event.explicitOriginalTarget.QueryInterface(
+                        Components.interfaces.nsIDOMElement);
+      var name = element.localName.toLowerCase();
+      if (name != "body" && name != "table" &&
+          name != "td" && name != "th" && name != "caption" && name != "tr")
+      {          
+        GetCurrentEditor().selectElement(event.explicitOriginalTarget);
+        event.preventDefault();
+      }
+    } catch (e) {}
+  }
+}
+
+/*TODO: We need an oncreate hook to do enabling/disabling for the
+        Format menu. There should be code like this for the
+        object-specific "Properties" item
+*/
+// For property dialogs, we want the selected element,
+//  but will accept a parent link, list, or table cell if inside one
+function GetObjectForProperties()
+{
+  var editor = GetCurrentEditor();
+  if (!editor || !IsHTMLEditor())
+    return null;
+
+  var element;
+  try {
+    element = editor.getSelectedElement("");
+  } catch (e) {}
+  if (element)
+    return element;
+
+  // Find nearest parent of selection anchor node
+  //   that is a link, list, table cell, or table
+
+  var anchorNode
+  var node;
+  try {
+    anchorNode = editor.selection.anchorNode;
+    if (anchorNode.firstChild)
+    {
+      // Start at actual selected node
+      var offset = editor.selection.anchorOffset;
+      // Note: If collapsed, offset points to element AFTER caret,
+      //  thus node may be null
+      node = anchorNode.childNodes.item(offset);
+    }
+    if (!node)
+      node = anchorNode;
+  } catch (e) {}
+
+  while (node)
+  {
+    if (node.nodeName)
+    {
+      var nodeName = node.nodeName.toLowerCase();
+
+      // Done when we hit the body
+      if (nodeName == "body") break;
+
+      if ((nodeName == "a" && node.href) ||
+          nodeName == "ol" || nodeName == "ul" || nodeName == "dl" ||
+          nodeName == "td" || nodeName == "th" ||
+          nodeName == "table")
+      {
+        return node;
+      }
+    }
+    node = node.parentNode;
+  }
+  return null;
+}
+
+function SetEditMode(mode)
+{
+  if (!IsHTMLEditor())
+    return;
+
+  var bodyElement = GetBodyElement();
+  if (!bodyElement)
+  {
+    dump("SetEditMode: We don't have a body node!\n");
+    return;
+  }
+
+  // must have editor if here!
+  var editor = GetCurrentEditor();
+  var inlineSpellCheckItem = document.getElementById('menu_inlinespellcheck');
+
+  // Switch the UI mode before inserting contents
+  //   so user can't type in source window while new window is being filled
+  var previousMode = gEditorDisplayMode;
+  if (!SetDisplayMode(mode))
+    return;
+
+  if (mode == kDisplayModeSource)
+  {
+    // Display the DOCTYPE as a non-editable string above edit area
+    var domdoc;
+    try { domdoc = editor.document; } catch (e) { dump( e + "\n");}
+    if (domdoc)
+    {
+      var doctypeNode = document.getElementById("doctype-text");
+      var dt = domdoc.doctype;
+      if (doctypeNode)
+      {
+        if (dt)
+        {
+          doctypeNode.collapsed = false;
+          var doctypeText = "<!DOCTYPE " + domdoc.doctype.name;
+          if (dt.publicId)
+            doctypeText += " PUBLIC \"" + domdoc.doctype.publicId;
+          if (dt.systemId)
+            doctypeText += " "+"\"" + dt.systemId;
+          doctypeText += "\">"
+          doctypeNode.setAttribute("value", doctypeText);
+        }
+        else
+          doctypeNode.collapsed = true;
+      }
+    }
+    // Get the entire document's source string
+
+    var flags = (editor.documentCharacterSet == "ISO-8859-1")
+      ? kOutputEncodeLatin1Entities
+      : kOutputEncodeBasicEntities;
+    try { 
+      var encodeEntity = gPrefs.getCharPref("editor.encode_entity");
+      switch (encodeEntity) {
+        case "basic"  : flags = kOutputEncodeBasicEntities; break;
+        case "latin1" : flags = kOutputEncodeLatin1Entities; break;
+        case "html"   : flags = kOutputEncodeHTMLEntities; break;
+        case "none"   : flags = 0;     break;
+      }
+    } catch (e) { }
+
+    try { 
+      var prettyPrint = gPrefs.getBoolPref("editor.prettyprint");
+      if (prettyPrint)
+        flags |= kOutputFormatted;
+
+    } catch (e) {}
+
+    flags |= kOutputLFLineBreak;
+    var source = editor.outputToString(kHTMLMimeType, flags);
+    var start = source.search(/<html/i);
+    if (start == -1) start = 0;
+    gSourceTextEditor.insertText(source.slice(start));
+    gSourceTextEditor.resetModificationCount();
+    gSourceTextEditor.addDocumentStateListener(gSourceTextListener);
+    gSourceTextEditor.enableUndo(true);
+    gSourceContentWindow.commandManager.addCommandObserver(gSourceTextObserver, "cmd_undo");
+    gSourceContentWindow.contentWindow.focus();
+    goDoCommand("cmd_moveTop");
+  }
+  else if (previousMode == kDisplayModeSource)
+  {
+    // Only rebuild document if a change was made in source window
+    if (IsHTMLSourceChanged())
+    {
+      // Disable spell checking when rebuilding source
+      InlineSpellCheckerUI.enabled = false;
+      inlineSpellCheckItem.removeAttribute('checked');
+
+      // Reduce the undo count so we don't use too much memory
+      //   during multiple uses of source window 
+      //   (reinserting entire doc caches all nodes)
+      try {
+        editor.transactionManager.maxTransactionCount = 1;
+      } catch (e) {}
+
+      editor.beginTransaction();
+      try {
+        // We are coming from edit source mode,
+        //   so transfer that back into the document
+        source = gSourceTextEditor.outputToString(kTextMimeType, kOutputLFLineBreak);
+        editor.rebuildDocumentFromSource(source);
+
+        // Get the text for the <title> from the newly-parsed document
+        // (must do this for proper conversion of "escaped" characters)
+        var title = "";
+        var titlenodelist = editor.document.getElementsByTagName("title");
+        if (titlenodelist)
+        {
+          var titleNode = titlenodelist.item(0);
+          if (titleNode && titleNode.firstChild && titleNode.firstChild.data)
+            title = titleNode.firstChild.data;
+        }
+        if (editor.document.title != title)
+          SetDocumentTitle(title);
+
+      } catch (ex) {
+        dump(ex);
+      }
+      editor.endTransaction();
+
+      // Restore unlimited undo count
+      try {
+        editor.transactionManager.maxTransactionCount = -1;
+      } catch (e) {}
+    }
+
+    // Clear out the string buffers
+    gSourceContentWindow.commandManager.removeCommandObserver(gSourceTextObserver, "cmd_undo");
+    gSourceTextEditor.removeDocumentStateListener(gSourceTextListener);
+    gSourceTextEditor.enableUndo(false);
+    gSourceTextEditor.selectAll();
+    gSourceTextEditor.deleteSelection(gSourceTextEditor.eNone);
+    gSourceTextEditor.resetModificationCount();
+
+    gContentWindow.focus();
+  }
+
+  switch (mode) {
+    case kDisplayModePreview:
+      // Disable spell checking when previewing
+      InlineSpellCheckerUI.enabled = false;
+      inlineSpellCheckItem.removeAttribute('checked');
+      // fall through
+    case kDisplayModeSource:
+      inlineSpellCheckItem.setAttribute('disabled', 'true');
+      break;
+    default:
+      inlineSpellCheckItem.setAttribute('disabled', !InlineSpellCheckerUI.canSpellCheck);
+      break;
+  }
+}
+
+function CancelHTMLSource()
+{
+  // Don't convert source text back into the DOM document
+  gSourceTextEditor.resetModificationCount();
+  SetDisplayMode(gPreviousNonSourceDisplayMode);
+}
+
+function FinishHTMLSource()
+{
+  //Here we need to check whether the HTML source contains <head> and <body> tags
+  //Or RebuildDocumentFromSource() will fail.
+  if (IsInHTMLSourceMode())
+  {
+    var htmlSource = gSourceTextEditor.outputToString(kTextMimeType, kOutputLFLineBreak);
+    if (htmlSource.length > 0)
+    {
+      var beginHead = htmlSource.indexOf("<head");
+      if (beginHead == -1)
+      {
+        AlertWithTitle(GetString("Alert"), GetString("NoHeadTag"));
+        //cheat to force back to Source Mode
+        gEditorDisplayMode = kDisplayModePreview;
+        SetDisplayMode(kDisplayModeSource);
+        throw Components.results.NS_ERROR_FAILURE;
+      }
+
+      var beginBody = htmlSource.indexOf("<body");
+      if (beginBody == -1)
+      {
+        AlertWithTitle(GetString("Alert"), GetString("NoBodyTag"));
+        //cheat to force back to Source Mode
+        gEditorDisplayMode = kDisplayModePreview;
+        SetDisplayMode(kDisplayModeSource);
+        throw Components.results.NS_ERROR_FAILURE;
+      }
+    }
+  }
+
+  // Switch edit modes -- converts source back into DOM document
+  SetEditMode(gPreviousNonSourceDisplayMode);
+}
+
+function SetDisplayMode(mode)
+{
+  if (!IsHTMLEditor())
+    return false;
+
+  // Already in requested mode:
+  //  return false to indicate we didn't switch
+  if (mode == gEditorDisplayMode)
+    return false;
+
+  var previousMode = gEditorDisplayMode;
+  gEditorDisplayMode = mode;
+
+  ResetStructToolbar();
+  if (mode == kDisplayModeSource)
+  {
+    // Switch to the sourceWindow (second in the deck)
+    gContentWindowDeck.selectedIndex = 1;
+
+    //Hide the formatting toolbar if not already hidden
+    gFormatToolbarHidden = gFormatToolbar.hidden;
+    gFormatToolbar.hidden = true;
+    gViewFormatToolbar.hidden = true;
+
+    gSourceContentWindow.contentWindow.focus();
+  }
+  else
+  {
+    // Save the last non-source mode so we can cancel source editing easily
+    gPreviousNonSourceDisplayMode = mode;
+
+    // Load/unload appropriate override style sheet
+    try {
+      var editor = GetCurrentEditor();
+      editor.QueryInterface(nsIEditorStyleSheets);
+      editor instanceof Components.interfaces.nsIHTMLObjectResizer;
+
+      switch (mode)
+      {
+        case kDisplayModePreview:
+          // Disable all extra "edit mode" style sheets 
+          editor.enableStyleSheet(kNormalStyleSheet, false);
+          editor.enableStyleSheet(kAllTagsStyleSheet, false);
+          editor.isImageResizingEnabled = true;
+          break;
+
+        case kDisplayModeNormal:
+          editor.addOverrideStyleSheet(kNormalStyleSheet);
+          // Disable ShowAllTags mode
+          editor.enableStyleSheet(kAllTagsStyleSheet, false);
+          editor.isImageResizingEnabled = true;
+          break;
+
+        case kDisplayModeAllTags:
+          editor.addOverrideStyleSheet(kNormalStyleSheet);
+          editor.addOverrideStyleSheet(kAllTagsStyleSheet);
+          // don't allow resizing in AllTags mode because the visible tags
+          // change the computed size of images and tables...
+          if (editor.resizedObject) {
+            editor.hideResizers();
+          }
+          editor.isImageResizingEnabled = false;
+          break;
+      }
+    } catch(e) {}
+
+    // Switch to the normal editor (first in the deck)
+    gContentWindowDeck.selectedIndex = 0;
+
+    // Restore menus and toolbars
+    gFormatToolbar.hidden = gFormatToolbarHidden;
+    gViewFormatToolbar.hidden = false;
+
+    gContentWindow.focus();
+  }
+
+  // update commands to disable or re-enable stuff
+  window.updateCommands("mode_switch");
+
+  // Set the selected tab at bottom of window:
+  // (Note: Setting "selectedIndex = mode" won't redraw tabs when menu is used.)
+  document.getElementById("EditModeTabs").selectedItem = document.getElementById(kDisplayModeTabIDS[mode]);
+
+  // Uncheck previous menuitem and set new check since toolbar may have been used
+  if (previousMode >= 0)
+    document.getElementById(kDisplayModeMenuIDs[previousMode]).setAttribute("checked","false");
+  document.getElementById(kDisplayModeMenuIDs[mode]).setAttribute("checked","true");
+  
+
+  return true;
+}
+
+function EditorToggleParagraphMarks()
+{
+  var menuItem = document.getElementById("viewParagraphMarks");
+  if (menuItem)
+  {
+    // Note that the 'type="checbox"' mechanism automatically
+    //  toggles the "checked" state before the oncommand is called,
+    //  so if "checked" is true now, it was just switched to that mode
+    var checked = menuItem.getAttribute("checked");
+    try {
+      var editor = GetCurrentEditor();
+      editor.QueryInterface(nsIEditorStyleSheets);
+
+      if (checked == "true")
+        editor.addOverrideStyleSheet(kParagraphMarksStyleSheet);
+      else
+        editor.enableStyleSheet(kParagraphMarksStyleSheet, false);
+    }
+    catch(e) { return; }
+  }
+}
+
+function InitPasteAsMenu()
+{
+  var menuItem = document.getElementById("menu_pasteTable")
+  if(menuItem)
+  {
+    menuItem.IsInTable  
+    menuItem.setAttribute("label", GetString(IsInTable() ? "NestedTable" : "Table"));
+   // menuItem.setAttribute("accesskey",GetString("ObjectPropertiesAccessKey"));
+  }
+  // TODO: Do enabling based on what is in the clipboard
+}
+
+function UpdateWindowTitle()
+{
+  try {
+    var windowTitle = GetDocumentTitle();
+    if (!windowTitle)
+      windowTitle = GetString("untitled");
+
+    // Append just the 'leaf' filename to the Doc. Title for the window caption
+    var docUrl = GetDocumentUrl();
+    if (docUrl && !IsUrlAboutBlank(docUrl))
+    {
+      var scheme = GetScheme(docUrl);
+      var filename = GetFilename(docUrl);
+      if (filename)
+        windowTitle += " [" + scheme + ":/.../" + filename + "]";
+
+      // Save changed title in the recent pages data in prefs
+      SaveRecentFilesPrefs();
+    }
+    // Set window title with " - Composer" appended
+    var xulWin = document.documentElement;
+    document.title = windowTitle + xulWin.getAttribute("titlemenuseparator") + 
+                     xulWin.getAttribute("titlemodifier");
+  } catch (e) { dump(e); }
+}
+
+function BuildRecentPagesMenu()
+{
+  var editor = GetCurrentEditor();
+  if (!editor || !gPrefs)
+    return;
+
+  var popup = document.getElementById("menupopup_RecentFiles");
+  if (!popup || !editor.document)
+    return;
+
+  // Delete existing menu
+  while (popup.firstChild)
+    popup.removeChild(popup.firstChild);
+
+  // Current page is the "0" item in the list we save in prefs,
+  //  but we don't include it in the menu.
+  var curUrl = StripPassword(GetDocumentUrl());
+  var historyCount = 10;
+  try {
+    historyCount = gPrefs.getIntPref("editor.history.url_maximum");
+  } catch(e) {}
+  var menuIndex = 1;
+
+  for (var i = 0; i < historyCount; i++)
+  {
+    var url = GetUnicharPref("editor.history_url_"+i);
+
+    // Skip over current url
+    if (url && url != curUrl)
+    {
+      // Build the menu
+      var title = GetUnicharPref("editor.history_title_"+i);
+      AppendRecentMenuitem(popup, title, url, menuIndex);
+      menuIndex++;
+    }
+  }
+}
+
+function SaveRecentFilesPrefs()
+{
+  // Can't do anything if no prefs
+  if (!gPrefs) return;
+
+  var curUrl = StripPassword(GetDocumentUrl());
+  var historyCount = 10;
+  try {
+    historyCount = gPrefs.getIntPref("editor.history.url_maximum"); 
+  } catch(e) {}
+
+  var titleArray = [];
+  var urlArray = [];
+
+  if (historyCount && !IsUrlAboutBlank(curUrl) &&  GetScheme(curUrl) != "data")
+  {
+    titleArray.push(GetDocumentTitle());
+    urlArray.push(curUrl);
+  }
+
+  for (var i = 0; i < historyCount && urlArray.length < historyCount; i++)
+  {
+    var url = GetUnicharPref("editor.history_url_"+i);
+
+    // Continue if URL pref is missing because 
+    //  a URL not found during loading may have been removed
+
+    // Skip over current an "data" URLs
+    if (url && url != curUrl && GetScheme(url) != "data")
+    {
+      var title = GetUnicharPref("editor.history_title_"+i);
+      titleArray.push(title);
+      urlArray.push(url);
+    }
+  }
+
+  // Resave the list back to prefs in the new order
+  for (i = 0; i < urlArray.length; i++)
+  {
+    SetUnicharPref("editor.history_title_"+i, titleArray[i]);
+    SetUnicharPref("editor.history_url_"+i, urlArray[i]);
+  }
+}
+
+function AppendRecentMenuitem(menupopup, title, url, menuIndex)
+{
+  if (menupopup)
+  {
+    var menuItem = document.createElementNS(XUL_NS, "menuitem");
+    if (menuItem)
+    {
+      var accessKey;
+      if (menuIndex <= 9)
+        accessKey = String(menuIndex);
+      else if (menuIndex == 10)
+        accessKey = "0";
+      else
+        accessKey = " ";
+
+      var itemString = accessKey+" ";
+
+      // Show "title [url]" or just the URL
+      if (title)
+      {
+       itemString += title;
+       itemString += " [";
+      }
+      itemString += url;
+      if (title)
+        itemString += "]";
+
+      menuItem.setAttribute("label", itemString);
+      menuItem.setAttribute("crop", "center");
+      menuItem.setAttribute("value", url);
+      if (accessKey != " ")
+        menuItem.setAttribute("accesskey", accessKey);
+      menupopup.appendChild(menuItem);
+    }
+  }
+}
+
+function EditorInitFileMenu()
+{
+  // Disable "Save" menuitem when editing remote url. User should use "Save As"
+  var docUrl = GetDocumentUrl();
+  var scheme = GetScheme(docUrl);
+  if (scheme && scheme != "file")
+    SetElementEnabledById("saveMenuitem", false);
+
+  // Enable recent pages submenu if there are any history entries in prefs
+  var historyUrl = "";
+
+  var historyCount = 10;
+  try { historyCount = gPrefs.getIntPref("editor.history.url_maximum"); } catch(e) {}
+  if (historyCount)
+  {
+    historyUrl = GetUnicharPref("editor.history_url_0");
+    
+    // See if there's more if current file is only entry in history list
+    if (historyUrl && historyUrl == docUrl)
+      historyUrl = GetUnicharPref("editor.history_url_1");
+  }
+  SetElementEnabledById("menu_RecentFiles", historyUrl != "");
+}
+
+function EditorInitFormatMenu()
+{
+  try {
+    InitObjectPropertiesMenuitem("objectProperties");
+    InitRemoveStylesMenuitems("removeStylesMenuitem", "removeLinksMenuitem", "removeNamedAnchorsMenuitem");
+  } catch(ex) {}
+}
+
+function InitObjectPropertiesMenuitem(id)
+{
+  // Set strings and enable for the [Object] Properties item
+  // Note that we directly do the enabling instead of
+  //  using goSetCommandEnabled since we already have the menuitem
+  var menuItem = document.getElementById(id);
+  if (!menuItem) return null;
+
+  var element;
+  var menuStr = GetString("AdvancedProperties");
+  var name;
+
+  if (IsEditingRenderedHTML())
+    element = GetObjectForProperties();
+
+  if (element && element.nodeName)
+  {
+    var objStr = "";
+    menuItem.setAttribute("disabled", "");
+    name = element.nodeName.toLowerCase();
+    switch (name)
+    {
+      case "img":
+        // Check if img is enclosed in link
+        //  (use "href" to not be fooled by named anchor)
+        try
+        {
+          if (GetCurrentEditor().getElementOrParentByTagName("href", element))
+            objStr = GetString("ImageAndLink");
+        } catch(e) {}
+        
+        if (objStr == "")
+          objStr = GetString("Image");
+        break;
+      case "hr":
+        objStr = GetString("HLine");
+        break;
+      case "table":
+        objStr = GetString("Table");
+        break;
+      case "th":
+        name = "td";
+      case "td":
+        objStr = GetString("TableCell");
+        break;
+      case "ol":
+      case "ul":
+      case "dl":
+        objStr = GetString("List");
+        break;
+      case "li":
+        objStr = GetString("ListItem");
+        break;
+      case "form":
+        objStr = GetString("Form");
+        break;
+      case "input":
+        var type = element.getAttribute("type");
+        if (type && type.toLowerCase() == "image")
+          objStr = GetString("InputImage");
+        else
+          objStr = GetString("InputTag");
+        break;
+      case "textarea":
+        objStr = GetString("TextArea");
+        break;
+      case "select":
+        objStr = GetString("Select");
+        break;
+      case "button":
+        objStr = GetString("Button");
+        break;
+      case "label":
+        objStr = GetString("Label");
+        break;
+      case "fieldset":
+        objStr = GetString("FieldSet");
+        break;
+      case "a":
+        if (element.name)
+        {
+          objStr = GetString("NamedAnchor");
+          name = "anchor";
+        }
+        else if(element.href)
+        {
+          objStr = GetString("Link");
+          name = "href";
+        }
+        break;
+    }
+    if (objStr)
+      menuStr = GetString("ObjectProperties").replace(/%obj%/,objStr);
+  }
+  else
+  {
+    // We show generic "Properties" string, but disable menu item
+    menuItem.setAttribute("disabled","true");
+  }
+  menuItem.setAttribute("label", menuStr);
+  menuItem.setAttribute("accesskey",GetString("ObjectPropertiesAccessKey"));
+  return name;
+}
+
+function InitParagraphMenu()
+{
+  var mixedObj = { value: null };
+  var state;
+  try {
+    state = GetCurrentEditor().getParagraphState(mixedObj);
+  }
+  catch(e) {}
+  var IDSuffix;
+
+  // PROBLEM: When we get blockquote, it masks other styles contained by it
+  // We need a separate method to get blockquote state
+
+  // We use "x" as uninitialized paragraph state
+  if (!state || state == "x")
+    IDSuffix = "bodyText" // No paragraph container
+  else
+    IDSuffix = state;
+
+  // Set "radio" check on one item, but...
+  var menuItem = document.getElementById("menu_"+IDSuffix);
+  menuItem.setAttribute("checked", "true");
+
+  // ..."bodyText" is returned if mixed selection, so remove checkmark
+  if (mixedObj.value)
+    menuItem.setAttribute("checked", "false");
+}
+
+function GetListStateString()
+{
+  try {
+    var editor = GetCurrentEditor();
+
+    var mixedObj = { value: null };
+    var hasOL = { value: false };
+    var hasUL = { value: false };
+    var hasDL = { value: false };
+    editor.getListState(mixedObj, hasOL, hasUL, hasDL);
+
+    if (mixedObj.value)
+      return "mixed";
+    if (hasOL.value)
+      return "ol";
+    if (hasUL.value)
+      return "ul";
+
+    if (hasDL.value)
+    {
+      var hasLI = { value: false };
+      var hasDT = { value: false };
+      var hasDD = { value: false };
+      editor.getListItemState(mixedObj, hasLI, hasDT, hasDD);
+      if (mixedObj.value)
+        return "mixed";
+      if (hasLI.value)
+        return "li";
+      if (hasDT.value)
+        return "dt";
+      if (hasDD.value)
+        return "dd";
+    }
+  } catch (e) {}
+
+  // return "noList" if we aren't in a list at all
+  return "noList";
+}
+
+function InitListMenu()
+{
+  if (!IsHTMLEditor())
+    return;
+
+  var IDSuffix = GetListStateString();
+
+  // Set enable state for the "None" menuitem
+  goSetCommandEnabled("cmd_removeList", IDSuffix != "noList");
+
+  // Set "radio" check on one item, but...
+  // we won't find a match if it's "mixed"
+  var menuItem = document.getElementById("menu_"+IDSuffix);
+  if (menuItem)
+    menuItem.setAttribute("checked", "true");
+}
+
+function GetAlignmentString()
+{
+  var mixedObj = { value: null };
+  var alignObj = { value: null };
+  try {
+    GetCurrentEditor().getAlignment(mixedObj, alignObj);
+  } catch (e) {}
+
+  if (mixedObj.value)
+    return "mixed";
+  if (alignObj.value == nsIHTMLEditor.eLeft)
+    return "left";
+  if (alignObj.value == nsIHTMLEditor.eCenter)
+    return "center";
+  if (alignObj.value == nsIHTMLEditor.eRight)
+    return "right";
+  if (alignObj.value == nsIHTMLEditor.eJustify)
+    return "justify";
+
+  // return "left" if we got here
+  return "left";
+}
+
+function InitAlignMenu()
+{
+  if (!IsHTMLEditor())
+    return;
+
+  var IDSuffix = GetAlignmentString();
+
+  // we won't find a match if it's "mixed"
+  var menuItem = document.getElementById("menu_"+IDSuffix);
+  if (menuItem)
+    menuItem.setAttribute("checked", "true");
+}
+
+function EditorSetDefaultPrefsAndDoctype()
+{
+  var editor = GetCurrentEditor();
+
+  var domdoc;
+  try { 
+    domdoc = editor.document;
+  } catch (e) { dump( e + "\n"); }
+  if ( !domdoc )
+  {
+    dump("EditorSetDefaultPrefsAndDoctype: EDITOR DOCUMENT NOT FOUND\n");
+    return;
+  }
+
+  // Insert a doctype element 
+  // if it is missing from existing doc
+  if (!domdoc.doctype)
+  {
+    var newdoctype = domdoc.implementation.createDocumentType("HTML", "-//W3C//DTD HTML 4.01 Transitional//EN","");
+    if (newdoctype)
+      domdoc.insertBefore(newdoctype, domdoc.firstChild);
+  }
+  
+  // search for head; we'll need this for meta tag additions
+  var headelement = 0;
+  var headnodelist = domdoc.getElementsByTagName("head");
+  if (headnodelist)
+  {
+    var sz = headnodelist.length;
+    if ( sz >= 1 )
+      headelement = headnodelist.item(0);
+  }
+  else
+  {
+    headelement = domdoc.createElement("head");
+    if (headelement)
+      domdoc.insertAfter(headelement, domdoc.firstChild);
+  }
+
+  /* only set default prefs for new documents */
+  if (!IsUrlAboutBlank(GetDocumentUrl()))
+    return;
+
+  // search for author meta tag.
+  // if one is found, don't do anything.
+  // if not, create one and make it a child of the head tag
+  //   and set its content attribute to the value of the editor.author preference.
+
+  var nodelist = domdoc.getElementsByTagName("meta");
+  if ( nodelist )
+  {
+    // we should do charset first since we need to have charset before
+    // hitting other 8-bit char in other meta tags
+    // grab charset pref and make it the default charset
+    var element;
+    var prefCharsetString = 0;
+    try
+    {
+      prefCharsetString = gPrefs.getComplexValue("intl.charset.default",
+                                                 Components.interfaces.nsIPrefLocalizedString).data;
+    }
+    catch (ex) {}
+    if ( prefCharsetString && prefCharsetString != 0)
+    {
+      editor.enableUndo(false);
+      editor.documentCharacterSet = prefCharsetString;
+      editor.resetModificationCount();
+      editor.enableUndo(true);
+    }
+
+    var node = 0;
+    var listlength = nodelist.length;
+
+    // let's start by assuming we have an author in case we don't have the pref
+    var authorFound = false;
+    for (var i = 0; i < listlength && !authorFound; i++)
+    {
+      node = nodelist.item(i);
+      if ( node )
+      {
+        var value = node.getAttribute("name");
+        if (value && value.toLowerCase() == "author")
+        {
+          authorFound = true;
+        }
+      }
+    }
+
+    var prefAuthorString = 0;
+    try
+    {
+      prefAuthorString = gPrefs.getComplexValue("editor.author",
+                                                Components.interfaces.nsISupportsString).data;
+    }
+    catch (ex) {}
+    if ( prefAuthorString && prefAuthorString != 0)
+    {
+      if ( !authorFound && headelement)
+      {
+        /* create meta tag with 2 attributes */
+        element = domdoc.createElement("meta");
+        if ( element )
+        {
+          element.setAttribute("name", "author");
+          element.setAttribute("content", prefAuthorString);
+          headelement.appendChild( element );
+        }
+      }
+    }
+  }
+
+  // add title tag if not present
+  var titlenodelist = editor.document.getElementsByTagName("title");
+  if (headelement && titlenodelist && titlenodelist.length == 0)
+  {
+     titleElement = domdoc.createElement("title");
+     if (titleElement)
+       headelement.appendChild(titleElement);
+  }
+
+  // Get editor color prefs
+  var use_custom_colors = false;
+  try {
+    use_custom_colors = gPrefs.getBoolPref("editor.use_custom_colors");
+  }
+  catch (ex) {}
+
+  // find body node
+  var bodyelement = GetBodyElement();
+  if (bodyelement)
+  {
+    if ( use_custom_colors )
+    {
+      // try to get the default color values.  ignore them if we don't have them.
+      var text_color;
+      var link_color;
+      var active_link_color;
+      var followed_link_color;
+      var background_color;
+
+      try { text_color = gPrefs.getCharPref("editor.text_color"); } catch (e) {}
+      try { link_color = gPrefs.getCharPref("editor.link_color"); } catch (e) {}
+      try { active_link_color = gPrefs.getCharPref("editor.active_link_color"); } catch (e) {}
+      try { followed_link_color = gPrefs.getCharPref("editor.followed_link_color"); } catch (e) {}
+      try { background_color = gPrefs.getCharPref("editor.background_color"); } catch(e) {}
+
+      // add the color attributes to the body tag.
+      // and use them for the default text and background colors if not empty
+      try {
+        if (text_color)
+        {
+          editor.setAttributeOrEquivalent(bodyelement, "text", text_color, true);
+          gDefaultTextColor = text_color;
+        }
+        if (background_color)
+        {
+          editor.setAttributeOrEquivalent(bodyelement, "bgcolor", background_color, true);
+          gDefaultBackgroundColor = background_color
+        }
+
+        if (link_color)
+          bodyelement.setAttribute("link", link_color);
+        if (active_link_color)
+          bodyelement.setAttribute("alink", active_link_color);
+        if (followed_link_color)
+          bodyelement.setAttribute("vlink", followed_link_color);
+      } catch (e) {}
+    }
+    // Default image is independent of Custom colors???
+    try {
+      var background_image = gPrefs.getCharPref("editor.default_background_image");
+      if (background_image)
+        editor.setAttributeOrEquivalent(bodyelement, "background", background_image, true);
+    } catch (e) {dump("BACKGROUND EXCEPTION: "+e+"\n"); }
+
+  }
+  // auto-save???
+}
+
+function GetBodyElement()
+{
+  try {
+    return GetCurrentEditor().rootElement;
+  }
+  catch (ex) {
+    dump("no body tag found?!\n");
+    //  better have one, how can we blow things up here?
+  }
+  return null;
+}
+
+// --------------------------- Logging stuff ---------------------------
+
+function EditorGetNodeFromOffsets(offsets)
+{
+  var node = null;
+  try {
+    node = GetCurrentEditor().document;
+
+    for (var i = 0; i < offsets.length; i++)
+      node = node.childNodes[offsets[i]];
+  } catch (e) {}
+  return node;
+}
+
+function EditorSetSelectionFromOffsets(selRanges)
+{
+  try {
+    var editor = GetCurrentEditor();
+    var selection = editor.selection;
+    selection.removeAllRanges();
+
+    var rangeArr, start, end, node, offset;
+    for (var i = 0; i < selRanges.length; i++)
+    {
+      rangeArr = selRanges[i];
+      start    = rangeArr[0];
+      end      = rangeArr[1];
+
+      var range = editor.document.createRange();
+
+      node   = EditorGetNodeFromOffsets(start[0]);
+      offset = start[1];
+
+      range.setStart(node, offset);
+
+      node   = EditorGetNodeFromOffsets(end[0]);
+      offset = end[1];
+
+      range.setEnd(node, offset);
+
+      selection.addRange(range);
+    }
+  } catch (e) {}
+}
+
+//--------------------------------------------------------------------
+function initFontStyleMenu(menuPopup)
+{
+  for (var i = 0; i < menuPopup.childNodes.length; i++)
+  {
+    var menuItem = menuPopup.childNodes[i];
+    var theStyle = menuItem.getAttribute("state");
+    if (theStyle)
+    {
+      menuItem.setAttribute("checked", theStyle);
+    }
+  }
+}
+
+//--------------------------------------------------------------------
+function onButtonUpdate(button, commmandID)
+{
+  var commandNode = document.getElementById(commmandID);
+  var state = commandNode.getAttribute("state");
+  button.checked = state == "true";
+}
+
+//--------------------------------------------------------------------
+function onStateButtonUpdate(button, commmandID, onState)
+{
+  var commandNode = document.getElementById(commmandID);
+  var state = commandNode.getAttribute("state");
+
+  button.checked = state == onState;
+}
+
+// --------------------------- Status calls ---------------------------
+function getColorAndSetColorWell(ColorPickerID, ColorWellID)
+{
+  var colorWell;
+  if (ColorWellID)
+    colorWell = document.getElementById(ColorWellID);
+
+  var colorPicker = document.getElementById(ColorPickerID);
+  if (colorPicker)
+  {
+    // Extract color from colorPicker and assign to colorWell.
+    var color = colorPicker.getAttribute("color");
+
+    if (colorWell && color)
+    {
+      // Use setAttribute so colorwell can be a XUL element, such as button
+      colorWell.setAttribute("style", "background-color: " + color);
+    }
+  }
+  return color;
+}
+
+//-----------------------------------------------------------------------------------
+function IsSpellCheckerInstalled()
+{
+  return "@mozilla.org/spellchecker;1" in Components.classes;
+}
+
+//-----------------------------------------------------------------------------------
+function IsFindInstalled()
+{
+  return "@mozilla.org/embedcomp/rangefind;1" in Components.classes
+          && "@mozilla.org/find/find_service;1" in Components.classes;
+}
+
+//-----------------------------------------------------------------------------------
+function RemoveInapplicableUIElements()
+{
+  // For items that are in their own menu block, remove associated separator
+  // (we can't use "hidden" since class="hide-in-IM" CSS rule interferes)
+
+   // if no find, remove find ui
+  if (!IsFindInstalled())
+  {
+    HideItem("menu_find");
+    HideItem("menu_findnext");
+    HideItem("menu_replace");
+    HideItem("menu_find");
+    RemoveItem("sep_find");
+  }
+
+   // if no spell checker, remove spell checker ui
+  if (!IsSpellCheckerInstalled())
+  {
+    HideItem("spellingButton");
+    HideItem("menu_checkspelling");
+    RemoveItem("sep_checkspelling");
+  }
+  else
+  {
+    SetElementEnabled(document.getElementById("menu_checkspelling"), true);
+    SetElementEnabled(document.getElementById("spellingButton"), true);
+    SetElementEnabled(document.getElementById("checkspellingkb"), true);
+  }
+
+  // Remove menu items (from overlay shared with HTML editor) in non-HTML.
+  if (!IsHTMLEditor())
+  {
+    HideItem("insertAnchor");
+    HideItem("insertImage");
+    HideItem("insertHline");
+    HideItem("insertTable");
+    HideItem("insertHTML");
+    HideItem("insertFormMenu");
+    HideItem("fileExportToText");
+    HideItem("viewFormatToolbar");
+    HideItem("viewEditModeToolbar");
+  }
+}
+
+function HideItem(id)
+{
+  var item = document.getElementById(id);
+  if (item)
+    item.hidden = true;
+}
+
+function RemoveItem(id)
+{
+  var item = document.getElementById(id);
+  if (item)
+    item.parentNode.removeChild(item);
+}
+
+// Command Updating Strategy:
+//   Don't update on on selection change, only when menu is displayed,
+//   with this "oncreate" hander:
+function EditorInitTableMenu()
+{
+  try {
+    InitJoinCellMenuitem("menu_JoinTableCells");
+  } catch (ex) {}
+
+  // Set enable states for all table commands
+  goUpdateTableMenuItems(document.getElementById("composerTableMenuItems"));
+}
+
+function InitJoinCellMenuitem(id)
+{
+  // Change text on the "Join..." item depending if we
+  //   are joining selected cells or just cell to right
+  // TODO: What to do about normal selection that crosses
+  //       table border? Try to figure out all cells
+  //       included in the selection?
+  var menuText;
+  var menuItem = document.getElementById(id);
+  if (!menuItem) return;
+
+  // Use "Join selected cells if there's more than 1 cell selected
+  var numSelected;
+  var foundElement;
+  
+  try {
+    var tagNameObj = {};
+    var countObj = {value:0}
+    foundElement = GetCurrentTableEditor().getSelectedOrParentTableElement(tagNameObj, countObj);
+    numSelected = countObj.value
+  }
+  catch(e) {}
+  if (foundElement && numSelected > 1)
+    menuText = GetString("JoinSelectedCells");
+  else
+    menuText = GetString("JoinCellToRight");
+
+  menuItem.setAttribute("label",menuText);
+  menuItem.setAttribute("accesskey",GetString("JoinCellAccesskey"));
+}
+
+function InitRemoveStylesMenuitems(removeStylesId, removeLinksId, removeNamedAnchorsId)
+{
+  var editor = GetCurrentEditor();
+  if (!editor)
+    return;
+
+  // Change wording of menuitems depending on selection
+  var stylesItem = document.getElementById(removeStylesId);
+  var linkItem = document.getElementById(removeLinksId);
+
+  var isCollapsed = editor.selection.isCollapsed;
+  if (stylesItem)
+  {
+    stylesItem.setAttribute("label", isCollapsed ? GetString("StopTextStyles") : GetString("RemoveTextStyles"));
+    stylesItem.setAttribute("accesskey", GetString("RemoveTextStylesAccesskey"));
+  }
+  if (linkItem)
+  {
+    linkItem.setAttribute("label", isCollapsed ? GetString("StopLinks") : GetString("RemoveLinks"));
+    linkItem.setAttribute("accesskey", GetString("RemoveLinksAccesskey"));
+    // Note: disabling text style is a pain since there are so many - forget it!
+
+    // Disable if not in a link, but always allow "Remove"
+    //  if selection isn't collapsed since we only look at anchor node
+    try {
+      SetElementEnabled(linkItem, !isCollapsed ||
+                      editor.getElementOrParentByTagName("href", null));
+    } catch(e) {}      
+  }
+  // Disable if selection is collapsed
+  SetElementEnabledById(removeNamedAnchorsId, !isCollapsed);
+}
+
+function goUpdateTableMenuItems(commandset)
+{
+  var editor = GetCurrentTableEditor();
+  if (!editor)
+  {
+    dump("goUpdateTableMenuItems: too early, not initialized\n");
+    return;
+  }
+
+  var enabled = false;
+  var enabledIfTable = false;
+
+  var flags = editor.flags;
+  if (!(flags & nsIPlaintextEditor.eEditorReadonlyMask) &&
+      IsEditingRenderedHTML())
+  {
+    var tagNameObj = { value: "" };
+    var element;
+    try {
+      element = editor.getSelectedOrParentTableElement(tagNameObj, {value:0});
+    }
+    catch(e) {}
+
+    if (element)
+    {
+      // Value when we need to have a selected table or inside a table
+      enabledIfTable = true;
+
+      // All others require being inside a cell or selected cell
+      enabled = (tagNameObj.value == "td");
+    }
+  }
+
+  // Loop through command nodes
+  for (var i = 0; i < commandset.childNodes.length; i++)
+  {
+    var commandID = commandset.childNodes[i].getAttribute("id");
+    if (commandID)
+    {
+      if (commandID == "cmd_InsertTable" ||
+          commandID == "cmd_JoinTableCells" ||
+          commandID == "cmd_SplitTableCell" ||
+          commandID == "cmd_ConvertToTable")
+      {
+        // Call the update method in the command class
+        goUpdateCommand(commandID);
+      }
+      // Directly set with the values calculated here
+      else if (commandID == "cmd_DeleteTable" ||
+               commandID == "cmd_NormalizeTable" ||
+               commandID == "cmd_editTable" ||
+               commandID == "cmd_TableOrCellColor" ||
+               commandID == "cmd_SelectTable")
+      {
+        goSetCommandEnabled(commandID, enabledIfTable);
+      } else {
+        goSetCommandEnabled(commandID, enabled);
+      }
+    }
+  }
+}
+
+//-----------------------------------------------------------------------------------
+// Helpers for inserting and editing tables:
+
+function IsInTable()
+{
+  var editor = GetCurrentEditor();
+  try {
+    var flags = editor.flags;
+    return (IsHTMLEditor() &&
+            !(flags & nsIPlaintextEditor.eEditorReadonlyMask) &&
+            IsEditingRenderedHTML() &&
+            null != editor.getElementOrParentByTagName("table", null));
+  } catch (e) {}
+  return false;
+}
+
+function IsInTableCell()
+{
+  try {
+    var editor = GetCurrentEditor();
+    var flags = editor.flags;
+    return (IsHTMLEditor() &&
+            !(flags & nsIPlaintextEditor.eEditorReadonlyMask) && 
+            IsEditingRenderedHTML() &&
+            null != editor.getElementOrParentByTagName("td", null));
+  } catch (e) {}
+  return false;
+
+}
+
+function IsSelectionInOneCell()
+{
+  try {
+    var editor = GetCurrentEditor();
+    var selection = editor.selection;
+
+    if (selection.rangeCount == 1)
+    {
+      // We have a "normal" single-range selection
+      if (!selection.isCollapsed &&
+         selection.anchorNode != selection.focusNode)
+      {
+        // Check if both nodes are within the same cell
+        var anchorCell = editor.getElementOrParentByTagName("td", selection.anchorNode);
+        var focusCell = editor.getElementOrParentByTagName("td", selection.focusNode);
+        return (focusCell != null && anchorCell != null && (focusCell == anchorCell));
+      }
+      // Collapsed selection or anchor == focus (thus must be in 1 cell)
+      return true;
+    }
+  } catch (e) {}
+  return false;
+}
+
+// Call this with insertAllowed = true to allow inserting if not in existing table,
+//   else use false to do nothing if not in a table
+function EditorInsertOrEditTable(insertAllowed)
+{
+  if (IsInTable())
+  {
+    // Edit properties of existing table
+    window.openDialog("chrome://editor/content/EdTableProps.xul", "_blank", "chrome,close,titlebar,modal", "","TablePanel");
+    gContentWindow.focus();
+  } 
+  else if (insertAllowed)
+  {
+    try {
+      if (GetCurrentEditor().selection.isCollapsed)
+        // If we have a caret, insert a blank table...
+        EditorInsertTable();
+      else
+        // else convert the selection into a table
+        goDoCommand("cmd_ConvertToTable");
+    } catch (e) {}
+  }
+}
+
+function EditorInsertTable()
+{
+  // Insert a new table
+  window.openDialog("chrome://editor/content/EdInsertTable.xul", "_blank", "chrome,close,titlebar,modal", "");
+  gContentWindow.focus();
+}
+
+function EditorTableCellProperties()
+{
+  if (!IsHTMLEditor())
+    return;
+
+  try {
+    var cell = GetCurrentEditor().getElementOrParentByTagName("td", null);
+    if (cell) {
+      // Start Table Properties dialog on the "Cell" panel
+      window.openDialog("chrome://editor/content/EdTableProps.xul", "_blank", "chrome,close,titlebar,modal", "", "CellPanel");
+      gContentWindow.focus();
+    }
+  } catch (e) {}
+}
+
+function GetNumberOfContiguousSelectedRows()
+{
+  if (!IsHTMLEditor())
+    return 0;
+
+  var rows = 0;
+  try {
+    var editor = GetCurrentTableEditor();
+    var rowObj = { value: 0 };
+    var colObj = { value: 0 };
+    var cell = editor.getFirstSelectedCellInTable(rowObj, colObj);
+    if (!cell)
+      return 0;
+
+    // We have at least one row
+    rows++;
+
+    var lastIndex = rowObj.value;
+    do {
+      cell = editor.getNextSelectedCell({value:0});
+      if (cell)
+      {
+        editor.getCellIndexes(cell, rowObj, colObj);
+        var index = rowObj.value;
+        if (index == lastIndex + 1)
+        {
+          lastIndex = index;
+          rows++;
+        }
+      }
+    }
+    while (cell);
+  } catch (e) {}
+
+  return rows;
+}
+
+function GetNumberOfContiguousSelectedColumns()
+{
+  if (!IsHTMLEditor())
+    return 0;
+
+  var columns = 0;
+  try {
+    var editor = GetCurrentTableEditor();
+    var colObj = { value: 0 };
+    var rowObj = { value: 0 };
+    var cell = editor.getFirstSelectedCellInTable(rowObj, colObj);
+    if (!cell)
+      return 0;
+
+    // We have at least one column
+    columns++;
+
+    var lastIndex = colObj.value;
+    do {
+      cell = editor.getNextSelectedCell({value:0});
+      if (cell)
+      {
+        editor.getCellIndexes(cell, rowObj, colObj);
+        var index = colObj.value;
+        if (index == lastIndex +1)
+        {
+          lastIndex = index;
+          columns++;
+        }
+      }
+    }
+    while (cell);
+  } catch (e) {}
+
+  return columns;
+}
+
+function EditorOnFocus()
+{
+  // Current window already has the InsertCharWindow
+  if ("InsertCharWindow" in window && window.InsertCharWindow) return;
+
+  // Find window with an InsertCharsWindow and switch association to this one
+  var windowWithDialog = FindEditorWithInsertCharDialog();
+  if (windowWithDialog)
+  {
+    // Switch the dialog to current window
+    // this sets focus to dialog, so bring focus back to editor window
+    if (SwitchInsertCharToThisWindow(windowWithDialog))
+      top.document.commandDispatcher.focusedWindow.focus();
+  }
+}
+
+function SwitchInsertCharToThisWindow(windowWithDialog)
+{
+  if (windowWithDialog && "InsertCharWindow" in windowWithDialog &&
+      windowWithDialog.InsertCharWindow)
+  {
+    // Move dialog association to the current window
+    window.InsertCharWindow = windowWithDialog.InsertCharWindow;
+    windowWithDialog.InsertCharWindow = null;
+
+    // Switch the dialog's opener to current window's
+    window.InsertCharWindow.opener = window;
+
+    // Bring dialog to the forground
+    window.InsertCharWindow.focus();
+    return true;
+  }
+  return false;
+}
+
+function FindEditorWithInsertCharDialog()
+{
+  try {
+    // Find window with an InsertCharsWindow and switch association to this one
+    var windowManager = Components.classes['@mozilla.org/appshell/window-mediator;1'].getService();
+    var windowManagerInterface = windowManager.QueryInterface( Components.interfaces.nsIWindowMediator);
+    var enumerator = windowManagerInterface.getEnumerator( null );
+
+    while ( enumerator.hasMoreElements()  )
+    {
+      var tempWindow = enumerator.getNext();
+
+      if (tempWindow != window && "InsertCharWindow" in tempWindow &&
+          tempWindow.InsertCharWindow)
+      {
+        return tempWindow;
+      }
+    }
+  }
+  catch(e) {}
+  return null;
+}
+
+function EditorFindOrCreateInsertCharWindow()
+{
+  if ("InsertCharWindow" in window && window.InsertCharWindow)
+    window.InsertCharWindow.focus();
+  else
+  {
+    // Since we switch the dialog during EditorOnFocus(),
+    //   this should really never be found, but it's good to be sure
+    var windowWithDialog = FindEditorWithInsertCharDialog();
+    if (windowWithDialog)
+    {
+      SwitchInsertCharToThisWindow(windowWithDialog);
+    }
+    else
+    {
+      // The dialog will set window.InsertCharWindow to itself
+      window.openDialog("chrome://editor/content/EdInsertChars.xul", "_blank", "chrome,close,titlebar", "");
+    }
+  }
+}
+
+// Find another HTML editor window to associate with the InsertChar dialog
+//   or close it if none found  (May be a mail composer)
+function SwitchInsertCharToAnotherEditorOrClose()
+{
+  if ("InsertCharWindow" in window && window.InsertCharWindow)
+  {
+    var windowManager = Components.classes['@mozilla.org/appshell/window-mediator;1'].getService();
+    var enumerator;
+    try {
+      var windowManagerInterface = windowManager.QueryInterface( Components.interfaces.nsIWindowMediator);
+      enumerator = windowManagerInterface.getEnumerator( null );
+    }
+    catch(e) {}
+    if (!enumerator) return;
+
+    // TODO: Fix this to search for command controllers and look for "cmd_InsertChars"
+    // For now, detect just Web Composer and HTML Mail Composer
+    while ( enumerator.hasMoreElements()  )
+    {
+      var  tempWindow = enumerator.getNext();
+      if (tempWindow != window && tempWindow != window.InsertCharWindow &&
+          "GetCurrentEditor" in tempWindow && tmpWindow.GetCurrentEditor())
+      {
+        tempWindow.InsertCharWindow = window.InsertCharWindow;
+        window.InsertCharWindow = null;
+        tempWindow.InsertCharWindow.opener = tempWindow;
+        return;
+      }
+    }
+    // Didn't find another editor - close the dialog
+    window.InsertCharWindow.close();
+  }
+}
+
+function ResetStructToolbar()
+{
+  gLastFocusNode = null;
+  UpdateStructToolbar();
+}
+
+function newCommandListener(element)
+{
+  return function() { return SelectFocusNodeAncestor(element); };
+}
+
+function newContextmenuListener(button, element)
+{
+  return function() { return InitStructBarContextMenu(button, element); };
+}
+
+function UpdateStructToolbar()
+{
+  var editor = GetCurrentEditor();
+  if (!editor) return;
+
+  var mixed = GetSelectionContainer();
+  if (!mixed) return;
+  var element = mixed.node;
+  var oneElementSelected = mixed.oneElementSelected;
+
+  if (!element) return;
+
+  if (element == gLastFocusNode &&
+      oneElementSelected == gLastFocusNodeWasSelected)
+    return;
+
+  gLastFocusNode = element;
+  gLastFocusNodeWasSelected = mixed.oneElementSelected;
+
+  var toolbar = document.getElementById("structToolbar");
+  if (!toolbar) return;
+  var childNodes = toolbar.childNodes;
+  var childNodesLength = childNodes.length;
+  // We need to leave the <label> to flex the buttons to the left
+  // so, don't remove the last child at position length - 1
+  while (childNodes.length > 1) {
+    // Remove back to front so there's less moving about.
+    toolbar.removeChild(childNodes.item(childNodes.length - 2));
+  }
+
+  toolbar.removeAttribute("label");
+
+  if ( IsInHTMLSourceMode() ) {
+    // we have destroyed the contents of the status bar and are
+    // about to recreate it ; but we don't want to do that in
+    // Source mode
+    return;
+  }
+
+  var tag, button;
+  var bodyElement = GetBodyElement();
+  var isFocusNode = true;
+  var tmp;
+  do {
+    tag = element.nodeName.toLowerCase();
+
+    button = document.createElementNS(XUL_NS, "toolbarbutton");
+    button.setAttribute("label",   "<" + tag + ">");
+    button.setAttribute("value",   tag);
+    button.setAttribute("context", "structToolbarContext");
+    button.className = "struct-button";
+
+    toolbar.insertBefore(button, toolbar.firstChild);
+
+    button.addEventListener("command", newCommandListener(element), false);
+
+    button.addEventListener("contextmenu", newContextmenuListener(button, element), false);
+
+    if (isFocusNode && oneElementSelected) {
+      button.setAttribute("checked", "true");
+      isFocusNode = false;
+    }
+
+    tmp = element;
+    element = element.parentNode;
+
+  } while (tmp != bodyElement);
+}
+
+function SelectFocusNodeAncestor(element)
+{
+  var editor = GetCurrentEditor();
+  if (editor) {
+    if (element == GetBodyElement())
+      editor.selectAll();
+    else
+      editor.selectElement(element);
+  }
+  ResetStructToolbar();
+}
+
+function GetSelectionContainer()
+{
+  var editor = GetCurrentEditor();
+  if (!editor) return null;
+
+  try {
+    var selection = editor.selection;
+    if (!selection) return null;
+  }
+  catch (e) { return null; }
+
+  var result = { oneElementSelected:false };
+
+  if (selection.isCollapsed) {
+    result.node = selection.focusNode;
+  }
+  else {
+    var rangeCount = selection.rangeCount;
+    if (rangeCount == 1) {
+      result.node = editor.getSelectedElement("");
+      var range = selection.getRangeAt(0);
+
+      // check for a weird case : when we select a piece of text inside
+      // a text node and apply an inline style to it, the selection starts
+      // at the end of the text node preceding the style and ends after the
+      // last char of the style. Assume the style element is selected for
+      // user's pleasure
+      if (!result.node &&
+          range.startContainer.nodeType == Node.TEXT_NODE &&
+          range.startOffset == range.startContainer.length &&
+          range.endContainer.nodeType == Node.TEXT_NODE &&
+          range.endOffset == range.endContainer.length &&
+          range.endContainer.nextSibling == null &&
+          range.startContainer.nextSibling == range.endContainer.parentNode)
+        result.node = range.endContainer.parentNode;
+
+      if (!result.node) {
+        // let's rely on the common ancestor of the selection
+        result.node = range.commonAncestorContainer;
+      }
+      else {
+        result.oneElementSelected = true;
+      }
+    }
+    else {
+      // assume table cells !
+      var i, container = null;
+      for (i = 0; i < rangeCount; i++) {
+        range = selection.getRangeAt(i);
+        if (!container) {
+          container = range.startContainer;
+        }
+        else if (container != range.startContainer) {
+          // all table cells don't belong to same row so let's
+          // select the parent of all rows
+          result.node = container.parentNode;
+          break;
+        }
+        result.node = container;
+      }
+    }
+  }
+
+  // make sure we have an element here
+  while (result.node.nodeType != Node.ELEMENT_NODE)
+    result.node = result.node.parentNode;
+
+  // and make sure the element is not a special editor node like
+  // the <br> we insert in blank lines
+  // and don't select anonymous content !!! (fix for bug 190279)
+  while (result.node.hasAttribute("_moz_editor_bogus_node") ||
+         editor.isAnonymousElement(result.node))
+    result.node = result.node.parentNode;
+
+  return result;
+}
+
+function FillInHTMLTooltipEditor(tooltip)
+{
+  const XLinkNS = "http://www.w3.org/1999/xlink";
+  var tooltipText = null;
+  var node;
+  if (gEditorDisplayMode == kDisplayModePreview) {
+    for (node = document.tooltipNode; node; node = node.parentNode) {
+      if (node.nodeType == Node.ELEMENT_NODE) {
+        tooltipText = node.getAttributeNS(XLinkNS, "title");
+        if (tooltipText && /\S/.test(tooltipText)) {
+          tooltip.setAttribute("label", tooltipText);
+          return true;
+        }
+        tooltipText = node.getAttribute("title");
+        if (tooltipText && /\S/.test(tooltipText)) {
+          tooltip.setAttribute("label", tooltipText);
+          return true;
+        }
+      }
+    }
+  } else {
+    for (node = document.tooltipNode; node; node = node.parentNode) {
+      if (node instanceof Components.interfaces.nsIDOMHTMLImageElement ||
+          node instanceof Components.interfaces.nsIDOMHTMLInputElement)
+        tooltipText = node.getAttribute("src");
+      else if (node instanceof Components.interfaces.nsIDOMHTMLAnchorElement)
+        tooltipText = node.getAttribute("href") || node.name;
+      if (tooltipText) {
+        tooltip.setAttribute("label", tooltipText);
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+function UpdateTOC()
+{
+  window.openDialog("chrome://editor/content/EdInsertTOC.xul",
+                    "_blank", "chrome,close,modal,titlebar");
+  window.content.focus();
+}
+
+function InitTOCMenu()
+{
+  var elt = GetCurrentEditor().document.getElementById("mozToc");
+  var createMenuitem = document.getElementById("insertTOCMenuitem");
+  var updateMenuitem = document.getElementById("updateTOCMenuitem");
+  var removeMenuitem = document.getElementById("removeTOCMenuitem");
+  if (removeMenuitem && createMenuitem && updateMenuitem) {
+    if (elt) {
+      createMenuitem.setAttribute("disabled", "true");
+      updateMenuitem.removeAttribute("disabled");
+      removeMenuitem.removeAttribute("disabled");
+    }
+    else {
+      createMenuitem.removeAttribute("disabled");
+      removeMenuitem.setAttribute("disabled", "true");
+      updateMenuitem.setAttribute("disabled", "true");
+    }
+  }
+}
+
+function RemoveTOC()
+{
+  var theDocument = GetCurrentEditor().document;
+  var elt = theDocument.getElementById("mozToc");
+  if (elt) {
+    elt.parentNode.removeChild(elt);
+  }
+
+  function acceptNode(node)
+  {
+    if (node.nodeName.toLowerCase() == "a" &&
+        node.hasAttribute("name") &&
+        node.getAttribute("name").substr(0, 8) == "mozTocId") {
+      return NodeFilter.FILTER_ACCEPT;
+    }
+    return NodeFilter.FILTER_SKIP;
+  }
+
+  var treeWalker = theDocument.createTreeWalker(theDocument.documentElement,
+                                                NodeFilter.SHOW_ELEMENT,
+                                                acceptNode,
+                                                true);
+  if (treeWalker) {
+    var anchorNode = treeWalker.nextNode();
+    while (anchorNode) {
+      var tmp = treeWalker.nextNode();
+      anchorNode.parentNode.removeChild(anchorNode);
+      anchorNode = tmp;
+    }
+  }
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/composer/content/editor.xul
@@ -0,0 +1,311 @@
+<?xml version="1.0"?> 
+
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1999-2000
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -   Ben Goodger
+   -   Michael Lowe
+   -   Sammy Ford
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/" type="text/css"?> 
+
+<?xml-stylesheet href="chrome://editor/skin/editorPrimaryToolbar.css" type="text/css"?> 
+<?xml-stylesheet href="chrome://editor/skin/editorFormatToolbar.css" type="text/css"?> 
+<?xml-stylesheet href="chrome://editor/skin/editorModeToolbar.css" type="text/css"?> 
+<?xul-overlay href="chrome://editor/content/editorOverlay.xul"?>
+<?xul-overlay href="chrome://editor/content/composerOverlay.xul"?>
+<?xul-overlay href="chrome://editor/content/EditorContextMenuOverlay.xul"?>
+<?xul-overlay href="chrome://global/content/globalOverlay.xul"?>
+<?xul-overlay href="chrome://global/content/charsetOverlay.xul"?>
+<?xul-overlay href="chrome://communicator/content/utilityOverlay.xul"?>
+<?xul-overlay href="chrome://communicator/content/tasksOverlay.xul"?>
+<?xul-overlay href="chrome://communicator/content/contentAreaContextOverlay.xul"?>
+<?xul-overlay href="chrome://communicator/content/sidebar/sidebarOverlay.xul"?>
+
+<!DOCTYPE window [
+<!ENTITY % editorDTD SYSTEM "chrome://editor/locale/editor.dtd" >
+%editorDTD;
+<!ENTITY % editorOverlayDTD SYSTEM "chrome://editor/locale/editorOverlay.dtd" >
+%editorOverlayDTD;
+<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" >
+%brandDTD;
+]> 
+
+<window id="editorWindow"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        onload="EditorOnLoad()"
+        onunload="EditorShutdown()"
+        onclose="return EditorCanClose()"
+        onfocus="EditorOnFocus()"
+        contenttitlesetting="true"
+        titlemodifier="&editorWindow.titlemodifier;"
+        titlemenuseparator="&editorWindow.titlemodifiermenuseparator;"
+        windowtype="composer:html"
+        width="640" height="480"
+        screenX="10" screenY="10"
+        persist="screenX screenY width height sizemode">
+
+  <script type="application/x-javascript" src="chrome://editor/content/editor.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EditorContextMenu.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/StructBarContextMenu.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/editorApplicationOverlay.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/publishprefs.js"/>
+  <script type="application/x-javascript" src="chrome://communicator/content/contentAreaDD.js"/>
+  <script type="application/x-javascript" src="chrome://communicator/content/contentAreaClick.js"/>
+  <script type="application/x-javascript" src="chrome://global/content/printUtils.js"/>
+  <script type="application/x-javascript" src="chrome://global/content/nsDragAndDrop.js"/>
+
+  <popupset id="editorContentContextSet"/>
+  <popup id="sidebarPopup"/>
+  <popup id="popupNotificationMenu"/>
+
+  <commandset id="tasksCommands">
+    <commandset id="globalEditMenuItems"/>
+    <commandset id="selectEditMenuItems"/>
+    <commandset id="undoEditMenuItems"/>
+    <commandset id="clipboardEditMenuItems"/>
+    
+    <commandset id="commonEditorMenuItems"/>
+    <commandset id="composerMenuItems"/>
+    <commandset id="composerEditMenuItems"/>
+    <commandset id="composerSaveMenuItems"/>    
+    <commandset id="composerStyleMenuItems"/>
+    <commandset id="composerTableMenuItems"/>
+    <commandset id="composerListMenuItems"/>
+    <command id="toggleSidebar"/>
+  </commandset>
+
+  <tooltip id="aHTMLTooltip" onpopupshowing="return FillInHTMLTooltipEditor(this);"/>
+
+  <broadcaster id="args" value="about:blank"/>
+  <broadcaster id="canPrint"/>
+  
+  <!-- Interim hack to transition from nsIXULWindowCallbacks/ShowWindowWithArgs
+  <broadcaster id="dialog.start" ready="false"/>
+  <observes element="dialog.start" attribute="ready" onbroadcast="EditorStartup('html')"/>
+-->
+  <broadcasterset id="broadcasterset">
+    <broadcaster id="Editor:Throbber" busy="false"/>
+    <broadcaster id="Communicator:WorkMode"/>
+  </broadcasterset>
+
+  <!-- keys are appended from the overlay -->
+  <keyset id="editorKeys">
+    <keyset id="tasksKeys"/>
+    <key id="showHideSidebar"/>
+    <!-- eat these tab events here to stop focus from moving -->
+    <key keycode="VK_TAB" oncommand="return true;"/>
+    <key keycode="VK_TAB" modifiers="shift" oncommand="return true;"/>
+    <key keycode="VK_TAB" modifiers="control" oncommand="return true;"/>
+    <key keycode="VK_TAB" modifiers="control,shift" oncommand="return true;"/>
+  </keyset>
+
+  <toolbox class="toolbox-top" id="EditorToolbox">
+  <menubar id="main-menubar" class="chromeclass-menubar" persist="collapsed" grippytooltiptext="&menuBar.tooltip;">
+    <menu id="fileMenu"/>
+    <menu id="editMenu"/>
+
+    <menu id="viewMenu" label="&viewMenu.label;" accesskey="&viewmenu.accesskey;">
+    <!-- id pulls in "Show Sidebar" item from sidebarOverlay -->
+    <menupopup id="menu_View_Popup">
+      <menu id="menu_Toolbars">
+        <menupopup id="view_toolbars_popup"> 
+          <menuitem id="viewComposerToolbar" label="&compositionToolbarCmd.label;" type="checkbox" accesskey="&compositiontb.accesskey;" command="cmd_viewCompToolbar"  />
+          <menuitem id="viewFormatToolbar"   label="&formattingToolbarCmd.label;"  type="checkbox" accesskey="&formattingtb.accesskey;"  command="cmd_viewFormatToolbar" />
+          <menuitem id="viewEditModeToolbar" label="&editmodeToolbarCmd.label;"    type="checkbox" accesskey="&editmodetb.accesskey;"    command="cmd_viewEditModeToolbar" />
+          <menuitem id="menu_showTaskbar"/>
+        </menupopup>
+      </menu>
+      <menuseparator id="viewSep1"/>
+      <menuitem id="viewNormalMode" checked="true"/>
+      <menuitem id="viewAllTagsMode"/>
+      <menuitem id="viewSourceMode"/>
+      <menuitem id="viewPreviewMode"/>
+      <menuseparator id="viewSep2"/>
+      <menu id = "composerCharsetMenu" />
+    </menupopup>
+    </menu>
+ 
+    <menu id="insertMenu"/>
+
+    <menu id="formatMenu" label="&formatMenu.label;" accesskey="&formatmenu.accesskey;">
+      <menupopup id="formatMenuPopup">
+        <menuitem id="snapToGrid"/>
+        <menuseparator/>
+        <menuitem id="objectProperties"/>
+        <menuitem id="colorsAndBackground"/>
+        <menuitem id="pageProperties"/>
+      </menupopup>
+    </menu>
+
+    <menu id="tableMenu"/>
+
+    <!-- tasks menu filled from tasksOverlay -->
+    <menu id="tasksMenu">
+      <menupopup id="taskPopup">
+        <menuitem id="menu_validate" observes="cmd_validate"/>
+        <menuseparator id="sep_validate"/>
+      </menupopup>
+    </menu>
+
+    <menu id="windowMenu"/>
+
+    <!-- help menu filled from globalOverlay -->
+    <menu id="menu_Help"/>
+
+    <spacer flex="1"/>
+  </menubar>
+
+  <!-- toolbar filled out from editorOverlay -->
+  <!-- add  class="standard" for dark blue background (icons need rework first) -->
+  <toolbar class="chromeclass-toolbar toolbar-primary" id="EditToolbar" persist="collapsed" 
+           grippytooltiptext="&compositionToolbar.tooltip;">
+    <toolbarbutton id="newButton"/>
+    <toolbarbutton id="openButton"/>
+    <toolbarbutton id="saveButton"/>
+    <toolbarbutton id="publishButton"/>
+    <toolbarbutton id="previewButton"/>
+    <toolbarbutton id="cutButton"/>
+    <toolbarbutton id="copyButton"/>
+    <toolbarbutton id="pasteButton"/>
+    <toolbarbutton id="printButton"/>
+    <toolbarbutton id="findButton"/>
+    <toolbarseparator class="toolbarseparator-primary"/>
+    <toolbarbutton id="linkButton"/>
+    <toolbarbutton id="namedAnchorButton"/>
+    <toolbarbutton id="imageButton"/>
+    <toolbarbutton id="hlineButton"/>
+    <toolbarbutton id="tableButton"/>
+    <toolbarbutton id="spellingButton"/>
+    <spacer flex="1"/>
+    <hbox id="throbber-box" align="center">
+      <button id="navigator-throbber" oncommand="goClickThrobber('editor.throbber.url')" tooltiptext="&throbber.tooltip;">
+        <observes element="Editor:Throbber" attribute="busy"/>
+      </button>
+    </hbox> 
+  </toolbar>
+  <toolbar class="chromeclass-toolbar" id="FormatToolbar" persist="collapsed" grippytooltiptext="&formatToolbar.tooltip;">
+    <!-- from editorOverlay -->
+    <menulist id="ParagraphSelect"/>
+    <stack id="ColorButtons"/>
+    <toolbarbutton id="HighlightColorButton"/>
+
+    <toolbarseparator class="toolbarseparator-standard"/>
+
+    <toolbarbutton id="DecreaseFontSizeButton"/>
+    <toolbarbutton id="IncreaseFontSizeButton"/>
+
+    <toolbarseparator class="toolbarseparator-standard"/>
+
+    <toolbarbutton id="boldButton"/>
+    <toolbarbutton id="italicButton"/>
+    <toolbarbutton id="underlineButton"/>
+
+    <toolbarseparator class="toolbarseparator-standard"/>
+    
+    <toolbarbutton id="ulButton"/>
+    <toolbarbutton id="olButton"/>
+    <toolbarbutton id="outdentButton"/>
+    <toolbarbutton id="indentButton"/>
+
+    <toolbarseparator class="toolbarseparator-standard"/>
+
+    <toolbarbutton id="align-left-button"/>
+    <toolbarbutton id="align-center-button"/>
+    <toolbarbutton id="align-right-button"/>
+    <toolbarbutton id="align-justify-button"/>
+
+    <toolbarbutton id="absolutePositionButton"/>
+    <toolbarbutton id="decreaseZIndexButton"/>
+    <toolbarbutton id="increaseZIndexButton"/>
+
+    <!-- TODO: Change to a menulist? -->
+    <!-- menu>
+      <button id="AlignPopupButton"/>
+      <menupopup id="AlignmentPopup"/>
+    </menu -->
+
+
+    <spacer flex="1"/>
+  </toolbar>
+</toolbox>
+
+<!-- sidebar/toolbar/content/status -->
+<hbox id="sidebar-parent" flex="1">
+  <!-- From sidebarOverlay.xul -->
+  <vbox id="sidebar-box" class="chromeclass-extrachrome" hidden="true"/>
+  <splitter id="sidebar-splitter" class="chromeclass-extrachrome" hidden="true"/>
+
+  <vbox id="appcontent" flex="1">
+    <deck id="ContentWindowDeck" selectedIndex="0" flex="1">
+      <!-- KLUDGE:  Temporary fix for bug 34414:
+           The current editor tag doesn't have a view, 
+           which breaks deck frame-hiding mechanism 
+       -->
+      <stack>
+        <editor editortype="html" type="content-primary" id="content-frame"
+                context="editorContentContext" flex="1" tooltip="aHTMLTooltip"/>
+      </stack>
+      <vbox>
+        <label id="doctype-text" crop="right"/>
+        <editor type="content" id="content-source" context="editorSourceContext" flex="1"/>
+      </vbox>
+    </deck>
+
+    <hbox id="EditModeToolbar" align="center" hidden="false" persist="collapsed">
+      <tabs id="EditModeTabs" class="tabs-bottom" flex="1">
+        <tab id="NormalModeButton"/>
+        <tab id="TagModeButton"/>
+        <tab id="SourceModeButton"/>
+        <tab id="PreviewModeButton"/>
+    </tabs>
+    </hbox>
+
+  </vbox> <!-- appcontent -->
+</hbox><!-- sidebar-parent -->
+
+    <!-- Some of this is from globarOverlay.xul -->
+    <statusbar class="chromeclass-status" id="status-bar">
+      <statusbarpanel id="component-bar"/>
+      <statusbarpanel id="structToolbar" flex="1" pack="end">
+	    <label id="structSpacer" value="" flex="1"/>
+      </statusbarpanel>
+      <statusbarpanel class="statusbarpanel-iconic" id="offline-status"/>
+    </statusbar>
+    
+
+
+</window>
new file mode 100644
--- /dev/null
+++ b/editor/ui/composer/content/editorApplicationOverlay.js
@@ -0,0 +1,169 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* Implementations of nsIControllerCommand for composer commands */
+
+function initEditorContextMenuItems(aEvent)
+{
+  var shouldShowEditPage = !gContextMenu.onImage && !gContextMenu.onLink && !gContextMenu.onTextInput && !gContextMenu.inDirList;
+  gContextMenu.showItem( "context-editpage", shouldShowEditPage );
+
+  var shouldShowEditLink = gContextMenu.onSaveableLink; 
+  gContextMenu.showItem( "context-editlink", shouldShowEditLink );
+
+  // Hide the applications separator if there's no add-on apps present. 
+  gContextMenu.showItem("context-sep-apps", gContextMenu.shouldShowSeparator("context-sep-apps"));
+}
+  
+function initEditorContextMenuListener(aEvent)
+{
+  var popup = document.getElementById("contentAreaContextMenu");
+  if (popup)
+    popup.addEventListener("popupshowing", initEditorContextMenuItems, false);
+}
+
+addEventListener("load", initEditorContextMenuListener, false);
+
+function editDocument(aDocument)      
+{
+  if (!aDocument)
+    aDocument = window.content.document;
+
+  editPage(aDocument.URL); 
+}
+
+function editPageOrFrame()
+{
+  var focusedWindow = document.commandDispatcher.focusedWindow;
+
+  // if the uri is a specific frame, grab it, else use the frameset uri 
+  // and let Composer handle error if necessary
+  editPage(getContentFrameURI(focusedWindow));
+}
+
+// Any non-editor window wanting to create an editor with a URL
+//   should use this instead of "window.openDialog..."
+//  We must always find an existing window with requested URL
+function editPage(url)
+{
+  // Always strip off "view-source:" and #anchors
+  url = url.replace(/^view-source:/, "").replace(/#.*/, "");
+
+  // if the current window is a browser window, then extract the current charset menu setting from the current 
+  // document and use it to initialize the new composer window...
+
+  var wintype = document.documentElement.getAttribute('windowtype');
+  var charsetArg;
+
+  if (wintype == "navigator:browser" && content.document)
+    charsetArg = "charset=" + content.document.characterSet;
+
+  try {
+    var uri = createURI(url, null, null);
+
+    var windowManager = Components.classes['@mozilla.org/appshell/window-mediator;1'].getService();
+    var windowManagerInterface = windowManager.QueryInterface( Components.interfaces.nsIWindowMediator);
+    var enumerator = windowManagerInterface.getEnumerator( "composer:html" );
+    var emptyWindow;
+    while ( enumerator.hasMoreElements() )
+    {
+      var win = enumerator.getNext().QueryInterface(Components.interfaces.nsIDOMWindowInternal);
+      if ( win && win.IsWebComposer())
+      {
+        if (CheckOpenWindowForURIMatch(uri, win))
+        {
+          // We found an editor with our url
+          win.focus();
+          return;
+        }
+        else if (!emptyWindow && win.PageIsEmptyAndUntouched())
+        {
+          emptyWindow = win;
+        }
+      }
+    }
+
+    if (emptyWindow)
+    {
+      // we have an empty window we can use
+      if (emptyWindow.IsInHTMLSourceMode())
+        emptyWindow.SetEditMode(emptyWindow.PreviousNonSourceDisplayMode);
+      emptyWindow.EditorLoadUrl(url);
+      emptyWindow.focus();
+      emptyWindow.SetSaveAndPublishUI(url);
+      return;
+    }
+
+    // Create new Composer window
+    openDialog("chrome://editor/content", "_blank", "chrome,all,dialog=no", url, charsetArg);
+
+  } catch(e) {}
+}
+
+function createURI(urlstring)
+{
+  try {
+    var ioserv = Components.classes["@mozilla.org/network/io-service;1"]
+               .getService(Components.interfaces.nsIIOService);
+    return ioserv.newURI(urlstring, null, null);
+  } catch (e) {}
+
+  return null;
+}
+
+function CheckOpenWindowForURIMatch(uri, win)
+{
+  try {
+    var contentWindow = win.content;  // need to QI win to nsIDOMWindowInternal?
+    var contentDoc = contentWindow.document;
+    var htmlDoc = contentDoc.QueryInterface(Components.interfaces.nsIDOMHTMLDocument);
+    var winuri = createURI(htmlDoc.URL);
+    return winuri.equals(uri);
+  } catch (e) {}
+  
+  return false;
+}
+
+function NewEditorFromTemplate()
+{
+  // XXX not implemented
+}
+
+function NewEditorFromDraft()
+{
+  // XXX not implemented
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/composer/content/editorMailOverlay.xul
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+
+<!-- retrieve generic commands -->
+<?xul-overlay href="chrome://messenger/content/mailOverlay.xul"?>
+
+<!DOCTYPE overlay SYSTEM "chrome://editor/locale/editorNavigatorOverlay.dtd" >
+
+<overlay id="editorMailOverlay"
+         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+  <script type="application/x-javascript" src="editorApplicationOverlay.js"/>
+
+  <!-- navigator specific commands -->
+  <commandset id="tasksCommands">
+    <!-- XXX insert commands here -->
+  </commandset>
+         
+  <!-- navigator specific UI items -->
+  <menupopup id="menu_NewPopup">
+    <!-- XXX insert File->New Menu add-ins here -->
+  </menupopup>
+
+  <menupopup id="menu_FilePopup">
+    <!-- XXX insert File Menu add-ins here -->
+  </menupopup>
+</overlay>
+
new file mode 100644
--- /dev/null
+++ b/editor/ui/composer/content/editorNavigatorOverlay.xul
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+
+<!-- retrieve generic commands -->
+<!-- <?xul-overlay href="chrome://messenger/content/mailOverlay.xul"?> -->
+
+<!DOCTYPE overlay SYSTEM "chrome://editor/locale/editorNavigatorOverlay.dtd" >
+
+<overlay id="editorNavigatorOverlay"
+         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+  <script type="application/x-javascript" src="editorApplicationOverlay.js"/>
+
+  <!-- navigator specific commands -->
+  <commandset id="tasksCommands">
+    <!-- XXX insert commands here -->
+  </commandset>
+         
+  <!-- navigator specific UI items -->
+  <menupopup id="menu_NewPopup">
+    <!-- XXX insert File->New Menu add-ins here -->
+  </menupopup>
+
+  <menupopup id="menu_FilePopup">
+    <!-- XXX insert File Menu add-ins here -->
+  </menupopup> 
+</overlay>
+
new file mode 100644
--- /dev/null
+++ b/editor/ui/composer/content/editorOverlay.js
@@ -0,0 +1,51 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+function EditorNew()
+{
+  dump("In EditorNew..\n");
+}
+
+function EditorNewFromTemplate()
+{
+  dump("In EditorNewFromTemplate..\n");
+}
+
+function EditorNewFromDraft()
+{
+  dump("In EditorNewFromDraft..\n");
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/composer/content/editorOverlay.xul
@@ -0,0 +1,918 @@
+<?xml version="1.0"?> 
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -   Ryan Cassin (rcassin@supernova.org)
+   -   Daniel Glazman (glazman@netscape.com)
+   -   Aaron Kaluszka (ask@swva.net)
+   -   Stephen Donner (technutz@netscape.net)
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!DOCTYPE overlay [
+<!ENTITY % editorOverlayDTD SYSTEM "chrome://editor/locale/editorOverlay.dtd">
+%editorOverlayDTD;
+<!ENTITY % platformCommunicatorDTD SYSTEM
+  "chrome://communicator-platform/locale/platformCommunicatorOverlay.dtd">
+%platformCommunicatorDTD;
+]>
+
+<overlay id="editorOverlay"
+         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+<script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+<script type="application/x-javascript" src="chrome://editor/content/ComposerCommands.js"/>
+
+  <keyset id="editorKeys">
+    <!-- defined in globalOverlay -->
+    <key id="key_newNavigator"/>
+    <key id="key_newBlankPage"/>
+
+    <key id="openeditorkb"   key="&fileopen.keybinding;"   observes="cmd_open"  modifiers="accel"/>
+    <key id="openremoteeditorkb"  key="&fileopenremote.keybinding;"  observes="cmd_openRemote"  modifiers="accel,shift"/>
+    <key id="savekb"         key="&filesave.keybinding;"   observes="cmd_save"   modifiers="accel"/>
+    <key id="publishkb"      key="&filesave.keybinding;"   observes="cmd_publish" modifiers="accel,shift"/>
+    <key id="closekb"        key="&fileclose.keybinding;"  observes="cmd_close"  modifiers="accel"/>
+    <key id="printkb"        key="&fileprint.keybinding;"  observes="cmd_print"  modifiers="accel"/>
+    <key id="key_quit"/>
+    <key id="key_undo"/>
+    <key id="key_redo"/>
+    <key id="key_cut"/>
+    <key id="key_copy"/>
+    <key id="key_paste"/>
+    <key id="key_delete"/>
+    <key id="key_selectAll"/>
+    <key id="pastequotationkb"  key="&editpastequotation.keybinding;"   observes="cmd_pasteQuote"  modifiers="accel, shift"/>
+    <key id="findkb"            key="&editfind.keybinding;"            observes="cmd_find"  modifiers="accel"/>
+    <key id="findnextkb"        key="&editfindnext.keybinding;"        observes="cmd_findNext"  modifiers="accel"/>
+    <key id="findprevkb"        key="&editfindprev.keybinding;"        observes="cmd_findPrev"  modifiers="accel,shift"/>
+    <key keycode="&editfindnext.keybinding2;" observes="cmd_findNext"/>
+    <key keycode="&editfindprev.keybinding2;" observes="cmd_findPrev" modifiers="shift"/>
+#ifdef MOZ_X11
+    <key keycode="&editfind.keybinding2;" observes="cmd_find"/>
+#endif
+    <key id="checkspellingkb"
+         key="&editcheckspelling.keybinding;"
+         observes="cmd_spelling"
+         modifiers="&accel.emacs_conflict;"
+         disabled="true"
+    />
+
+    <key id="boldkb"         key="&stylebold.keybinding;"       observes="cmd_bold" modifiers="accel"/>
+    <key id="italickb"       key="&styleitalic.keybinding;"     observes="cmd_italic" modifiers="accel"/>
+    <key id="underlinekb"    key="&styleunderline.keybinding;"  observes="cmd_underline" modifiers="accel"/>
+    <key id="fixedwidthkb"   key="&formatfontfixed.keybinding;" observes="cmd_tt" modifiers="accel"/>
+
+    <key id="increaseindentkb"  key="&formatindent.keybinding;"  observes="cmd_indent"  modifiers="accel"/>
+    <key id="decreaseindentkb"  key="&formatoutdent.keybinding;"  observes="cmd_outdent"  modifiers="accel"/>
+
+    <key id="removestyleskb"       key="&formatremovestyles.keybinding;"   observes="cmd_removeStyles"  modifiers="accel, shift"/>
+    <key id="removestyleskb2"       key=" "   observes="cmd_removeStyles"  modifiers="accel"/>
+    <key id="removelinkskb"        key="&formatremovelinks.keybinding;"    observes="cmd_removeLinks"  modifiers="accel, shift"/>
+    <key id="removenamedanchorskb" key="&formatremovenamedanchors.keybinding;"    observes="cmd_removeNamedAnchors"  modifiers="accel, shift"/>
+    <key id="decreasefontsizekb"   key="&decreaseFontSize.keybinding;"     observes="cmd_decreaseFont"  modifiers="accel"/>
+    <key id="increasefontsizekb"   key="&increaseFontSize.keybinding;"     observes="cmd_increaseFont"  modifiers="accel"/>
+    <key                           key="&increaseFontSize.keybinding;"     observes="cmd_increaseFont"  modifiers="accel,shift"/>
+    <key                           key="&increaseFontSize.keybinding2;"    observes="cmd_increaseFont"  modifiers="accel"/>
+
+    <key id="insertlinkkb"         key="&insertlink.keybinding;"           observes="cmd_link"          modifiers="accel"/>
+  </keyset>
+
+  <!-- commands updated when the editor gets created -->
+  <commandset id="commonEditorMenuItems"
+          commandupdater="true"
+          events="create"
+          oncommandupdate="goUpdateComposerMenuItems(this)"
+  >
+    <command id="cmd_open"                                          oncommand="goDoCommand('cmd_open')"/>
+    <command id="cmd_openRemote"   label="&openremoteCmd.label;"    oncommand="goDoCommand('cmd_openRemote')"/>
+    <command id="cmd_close"        label="&closeCmd.label;"         oncommand="goDoCommand('cmd_close')"/>
+    <command id="cmd_printSetup"   oncommand="goDoCommand('cmd_printSetup')"/>
+<!--
+    <command id="cmd_printPreview" label="&printPreviewCmd.label;"  oncommand="goDoCommand('cmd_printPreview')"/>
+-->
+    <command id="cmd_print"                                         oncommand="goDoCommand('cmd_print')"/>
+    <command id="cmd_quit"         oncommand="goDoCommand('cmd_quit')"/>
+  </commandset>
+
+  <commandset id="composerMenuItems"
+          commandupdater="true"
+          events="create, mode_switch"
+          oncommandupdate="goUpdateComposerMenuItems(this)"
+  >
+    <!-- format menu -->
+    <command id="cmd_listProperties"  oncommand="goDoCommand('cmd_listProperties')"/>
+    <command id="cmd_pageProperties"  oncommand="goDoCommand('cmd_pageProperties')"/>
+    <command id="cmd_colorProperties" oncommand="goDoCommand('cmd_colorProperties')"/>
+
+    <command id="cmd_link"             oncommand="goDoCommand('cmd_link')"/>
+    <command id="cmd_anchor"           oncommand="goDoCommand('cmd_anchor')"/>
+    <command id="cmd_image"            oncommand="goDoCommand('cmd_image')"/>
+    <command id="cmd_hline"            oncommand="goDoCommand('cmd_hline')"/>
+    <command id="cmd_table"            oncommand="goDoCommand('cmd_table')"/>
+    <command id="cmd_form"             oncommand="goDoCommand('cmd_form')"/>
+    <command id="cmd_inputtag"         oncommand="goDoCommand('cmd_inputtag')"/>
+    <command id="cmd_inputimage"       oncommand="goDoCommand('cmd_inputimage')"/>
+    <command id="cmd_textarea"         oncommand="goDoCommand('cmd_textarea')"/>
+    <command id="cmd_select"           oncommand="goDoCommand('cmd_select')"/>
+    <command id="cmd_button"           oncommand="goDoCommand('cmd_button')"/>
+    <command id="cmd_label"            oncommand="goDoCommand('cmd_label')"/>
+    <command id="cmd_fieldset"         oncommand="goDoCommand('cmd_fieldset')"/>
+    <command id="cmd_isindex"          oncommand="goDoCommand('cmd_isindex')"/>
+    <command id="cmd_objectProperties" oncommand="goDoCommand('cmd_objectProperties')"/>
+    <command id="cmd_insertChars"      oncommand="goDoCommand('cmd_insertChars')"    label="&insertCharsCmd.label;"/>
+    <command id="cmd_insertHTMLWithDialog" oncommand="goDoCommand('cmd_insertHTMLWithDialog')"  label="&insertHTMLCmd.label;"/>
+
+    <command id="cmd_insertBreak"      oncommand="goDoCommand('cmd_insertBreak')"/>
+    <command id="cmd_insertBreakAll"   oncommand="goDoCommand('cmd_insertBreakAll')"/>
+    <command id="cmd_NormalMode"       oncommand="goDoCommand('cmd_NormalMode')"     label="&NormalMode.label;"/>
+    <command id="cmd_AllTagsMode"      oncommand="goDoCommand('cmd_AllTagsMode')"    label="&AllTagsMode.label;"/>
+    <command id="cmd_HTMLSourceMode"   oncommand="goDoCommand('cmd_HTMLSourceMode')"/>
+    <command id="cmd_PreviewMode"      oncommand="goDoCommand('cmd_PreviewMode')"    label="&PreviewMode.label;"/>
+
+    <!-- only used in context popup menu -->
+    <command id="cmd_editLink"         oncommand="goDoCommand('cmd_editLink')"/>
+
+    <!-- dummy command used just to disable things in non-HTML modes -->
+    <command id="cmd_renderedHTMLEnabler"/>
+  </commandset>
+  
+  <commandset id="composerSaveMenuItems"
+          commandupdater="true"
+          events="create, save"
+          oncommandupdate="goUpdateComposerMenuItems(this)"
+  >
+    <command id="cmd_save"           label="&saveCmd.label;"           oncommand="goDoCommand('cmd_save')"/>
+    <command id="cmd_saveAs"         label="&saveAsCmd.label;"         oncommand="goDoCommand('cmd_saveAs')"/>
+    <command id="cmd_exportToText"   label="&exportToTextCmd.label;"   oncommand="goDoCommand('cmd_exportToText')"/>
+    <command id="cmd_saveAndChangeEncoding"  label="&saveAsChangeEncodingCmd.label;"  oncommand="goDoCommand('cmd_saveAndChangeEncoding')"/>
+    <command id="cmd_publish"        label="&publishCmd.label;"        oncommand="goDoCommand('cmd_publish')"/>
+    <command id="cmd_publishAs"      label="&publishAsCmd.label;"      oncommand="goDoCommand('cmd_publishAs')"/>
+    <command id="cmd_revert"         label="&fileRevert.label;"        oncommand="goDoCommand('cmd_revert')"/>
+    <command id="cmd_preview"                                          oncommand="goDoCommand('cmd_preview')"/>
+    <command id="cmd_editSendPage"   label="&sendPageCmd.label;"
+                                     accesskey="&sendPage.accesskey;"  oncommand="goDoCommand('cmd_editSendPage')"/>
+  </commandset>
+
+
+  <!-- edit menu commands. These get updated by code in globalOverlay.js -->
+  <commandset id="composerEditMenuItems"
+          commandupdater="true"
+          events="create, mode_switch"
+          oncommandupdate="goUpdateComposerMenuItems(this)"
+  >
+    <command id="cmd_undo"/>
+    <command id="cmd_redo"/>
+    <command id="cmd_cut"/>
+    <command id="cmd_copy"/>
+    <command id="cmd_paste"/>  
+    <command id="cmd_pasteNoFormatting" oncommand="goDoCommand('cmd_pasteNoFormatting')"
+             label="&pasteNoFormatting.label;" accesskey="&pasteNoFormatting.accesskey;"/>
+    <command id="cmd_delete"/>
+    <command id="cmd_selectAll"/>
+    <command id="cmd_preferences"   oncommand="goDoCommand('cmd_preferences')"/>
+    <command id="cmd_find"          oncommand="goDoCommand('cmd_find')"/>
+    <command id="cmd_findNext"      oncommand="goDoCommand('cmd_findNext')"     label="&findAgainCmd.label;"/>
+    <command id="cmd_findPrev"      oncommand="goDoCommand('cmd_findPrev')"     label="&findPrevCmd.label;"/>
+    <command id="cmd_spelling"      oncommand="goDoCommand('cmd_spelling')"/>
+    <command id="cmd_validate"      label="&validateCmd.label;" accesskey="&validate.accesskey;" oncommand="goDoCommand('cmd_validate')"/>
+    <command id="cmd_checkLinks"    oncommand="goDoCommand('cmd_checkLinks')"/>
+    <command id="cmd_pasteQuote"    oncommand="goDoCommand('cmd_pasteQuote')" label="&pasteAsQuotationCmd.label;"/>
+    <command id="cmd_publishSettings" label="&publishSettings.label;" accesskey="&publishSettings.accesskey;" oncommand="goDoCommand('cmd_publishSettings')"/>
+  </commandset>
+
+  <!-- style related commands that update on creation, and on selection change -->
+  <commandset id="composerStyleMenuItems"
+          commandupdater="true"
+          events="create, style, mode_switch"
+          oncommandupdate="goUpdateComposerMenuItems(this)"
+  >
+    <command id="cmd_bold"          state="false"     oncommand="doStyleUICommand('cmd_bold')"/>
+    <command id="cmd_italic"        state="false"     oncommand="doStyleUICommand('cmd_italic')"/>
+    <command id="cmd_underline"     state="false"     oncommand="doStyleUICommand('cmd_underline')"/>
+    <command id="cmd_tt"            state="false"     oncommand="doStyleUICommand('cmd_tt')"/>
+    <command id="cmd_smiley"/>
+
+    <command id="cmd_strikethrough" state="false"     oncommand="doStyleUICommand('cmd_strikethrough');"/>
+    <command id="cmd_superscript"   state="false"     oncommand="doStyleUICommand('cmd_superscript');"/>
+    <command id="cmd_subscript"     state="false"     oncommand="doStyleUICommand('cmd_subscript');"/>
+    <command id="cmd_nobreak"       state="false"     oncommand="doStyleUICommand('cmd_nobreak');"/>
+
+    <command id="cmd_em"            state="false"     oncommand="doStyleUICommand('cmd_em')"/>
+    <command id="cmd_strong"        state="false"     oncommand="doStyleUICommand('cmd_strong')"/>
+    <command id="cmd_cite"          state="false"     oncommand="doStyleUICommand('cmd_cite')"/>
+    <command id="cmd_abbr"          state="false"     oncommand="doStyleUICommand('cmd_abbr')"/>
+    <command id="cmd_acronym"       state="false"     oncommand="doStyleUICommand('cmd_acronym')"/>
+    <command id="cmd_code"          state="false"     oncommand="doStyleUICommand('cmd_code')"/>
+    <command id="cmd_samp"          state="false"     oncommand="doStyleUICommand('cmd_samp')"/>
+    <command id="cmd_var"           state="false"     oncommand="doStyleUICommand('cmd_var')"/>
+
+    <command id="cmd_ul"            state="false"     oncommand="doStyleUICommand('cmd_ul')"/>
+    <command id="cmd_ol"            state="false"     oncommand="doStyleUICommand('cmd_ol')"/>
+
+    <command id="cmd_indent"                          oncommand="goDoCommand('cmd_indent')"/>
+    <command id="cmd_outdent"                         oncommand="goDoCommand('cmd_outdent')"/>
+
+    <!-- the state attribute gets filled with the paragraph format before the command is exectued -->
+    <command id="cmd_paragraphState"  state=""         oncommand="doStatefulCommand('cmd_paragraphState', event.target.value)"/>
+    <command id="cmd_fontFace"        state=""         oncommand="doStatefulCommand('cmd_fontFace', event.target.value)"/>
+
+    <!-- No "oncommand", use EditorSelectColor() to bring up color dialog -->
+    <command id="cmd_fontColor"       state=""/>
+    <command id="cmd_backgroundColor" state=""/>
+    <command id="cmd_highlight"       state="transparent"  oncommand="EditorSelectColor('Highlight', event);"/>
+
+    <command id="cmd_fontSize"                         oncommand="goDoCommand('cmd_fontSize')"/>
+    <command id="cmd_align"           state=""/>
+
+    <command id="cmd_absPos"          state=""        oncommand="goDoCommand('cmd_absPos')"/>
+    <command id="cmd_increaseZIndex"  state=""        oncommand="goDoCommand('cmd_increaseZIndex')"/>
+    <command id="cmd_decreaseZIndex"  state=""        oncommand="goDoCommand('cmd_decreaseZIndex')"/>
+
+    <command id="cmd_advancedProperties"              oncommand="goDoCommand('cmd_advancedProperties')"/>
+
+    <command id="cmd_increaseFont"                    oncommand="goDoCommand('cmd_increaseFont')"/>
+    <command id="cmd_decreaseFont"                    oncommand="goDoCommand('cmd_decreaseFont')"/>
+    
+    <command id="cmd_removeStyles"                    oncommand="goDoCommand('cmd_removeStyles')"/>
+    <command id="cmd_removeLinks"                     oncommand="goDoCommand('cmd_removeLinks')"/>
+    <command id="cmd_removeNamedAnchors"              oncommand="goDoCommand('cmd_removeNamedAnchors')"/>
+    <command id="cmd_updateStructToolbar"             oncommand="goDoCommand('cmd_updateStructToolbar')"/>
+  </commandset>
+
+  <!-- commands updated only when the menu gets created -->
+  <commandset id="composerListMenuItems"
+          commandupdater="true"
+          events="create, mode_switch"
+          oncommandupdate="goUpdateComposerMenuItems(this)">
+    <!-- List menu  -->
+    <command id="cmd_dt"                  oncommand="doStyleUICommand('cmd_dt')"/>
+    <command id="cmd_dd"                  oncommand="doStyleUICommand('cmd_dd')"/>
+    <command id="cmd_removeList"          oncommand="goDoCommand('cmd_removeList')"/>
+    <!-- cmd_ul and cmd_ol are shared with toolbar and are in composerStyleMenuItems commandset -->
+  </commandset>
+
+  <commandset id="composerTableMenuItems"
+          commandupdater="true"
+          events="create, mode_switch"
+          oncommandupdate="goUpdateTableMenuItems(this)">
+    <!-- Table menu -->
+    <command id="cmd_SelectTable"         oncommand="goDoCommand('cmd_SelectTable')"/>
+    <command id="cmd_SelectRow"           oncommand="goDoCommand('cmd_SelectRow')"/>
+    <command id="cmd_SelectColumn"        oncommand="goDoCommand('cmd_SelectColumn')"/>
+    <command id="cmd_SelectCell"          oncommand="goDoCommand('cmd_SelectCell')"/>
+    <command id="cmd_SelectAllCells"      oncommand="goDoCommand('cmd_SelectAllCells')"/>
+    <command id="cmd_InsertTable"         oncommand="goDoCommand('cmd_InsertTable')"/>
+    <command id="cmd_InsertRowAbove"      oncommand="goDoCommand('cmd_InsertRowAbove')"/>
+    <command id="cmd_InsertRowBelow"      oncommand="goDoCommand('cmd_InsertRowBelow')"/>
+    <command id="cmd_InsertColumnBefore"  oncommand="goDoCommand('cmd_InsertColumnBefore')"/>
+    <command id="cmd_InsertColumnAfter"   oncommand="goDoCommand('cmd_InsertColumnAfter')"/>
+    <command id="cmd_InsertCellBefore"    oncommand="goDoCommand('cmd_InsertCellBefore')"/>
+    <command id="cmd_InsertCellAfter"     oncommand="goDoCommand('cmd_InsertCellAfter')"/>
+    <command id="cmd_DeleteTable"         oncommand="goDoCommand('cmd_DeleteTable')"/>
+    <command id="cmd_DeleteRow"           oncommand="goDoCommand('cmd_DeleteRow')"/>
+    <command id="cmd_DeleteColumn"        oncommand="goDoCommand('cmd_DeleteColumn')"/>
+    <command id="cmd_DeleteCell"          oncommand="goDoCommand('cmd_DeleteCell')"/>
+    <command id="cmd_DeleteCellContents"  oncommand="goDoCommand('cmd_DeleteCellContents')"/>
+    <command id="cmd_NormalizeTable"      oncommand="goDoCommand('cmd_NormalizeTable')"/>
+    <command id="cmd_JoinTableCells"      oncommand="goDoCommand('cmd_JoinTableCells')"/>
+    <command id="cmd_SplitTableCell"      oncommand="goDoCommand('cmd_SplitTableCell')"/>
+    <command id="cmd_ConvertToTable"      oncommand="goDoCommand('cmd_ConvertToTable')"/>
+    <command id="cmd_TableOrCellColor"    oncommand="goDoCommand('cmd_TableOrCellColor')"/>
+    <command id="cmd_editTable"           oncommand="goDoCommand('cmd_editTable')"/>
+  </commandset>
+
+  <broadcasterset id="broadcasterset">
+    <!-- Broadcasters/commands with no other home -->
+    <!-- view menu -->
+    <command id="cmd_newNavigator"/>
+    <command id="cmd_newEditor"/>
+    <command id="cmd_newEditorTemplate"/>
+    <command id="cmd_newEditorDraft"/>
+
+    <command id="cmd_viewCompToolbar"     oncommand="goToggleToolbar('EditToolbar','cmd_viewCompToolbar');"         checked="true"/>
+    <command id="cmd_viewFormatToolbar"   oncommand="goToggleToolbar('FormatToolbar','cmd_viewFormatToolbar');"     checked="true"/>
+    <command id="cmd_viewEditModeToolbar" oncommand="goToggleToolbar('EditModeToolbar','cmd_viewEditModeToolbar');" checked="true"/>
+
+    <!-- Obsolete; these will go away -->
+    <command id="Editor:Font:Size" fontsize=""/>
+  </broadcasterset>
+
+  <!-- File  menu items -->
+  <!-- Note: globalOverlay.xul uses menu_newEditor, but we want different menu item text
+             so we use our own id, label, and accesskey but connect to the same global key and broadcaster node
+   -->
+  <menu id="fileMenu" label="&fileMenu.label;" accesskey="&filemenu.accesskey;">
+    <menupopup id="menu_FilePopup" onpopupshowing="EditorInitFileMenu();">
+      <menu id="menu_New">
+        <menupopup id="menu_NewPopup">
+          <menuitem id="menu_newBlankPage" label="&newBlankPageCmd.label;" 
+                    accesskey="&newBlankPage.accesskey;" key="key_newBlankPage"
+                    command="cmd_newEditor"/>
+          <menuseparator id="composerBeginGlobalNewItems"/>
+          <!-- From globalOverlay.xul -->
+          <menuitem id="menu_newNavigator" observes="cmd_newNavigator"/>
+        </menupopup>
+      </menu>
+      <menuitem accesskey="&fileopenremote.accesskey;"      key="openremoteeditorkb" observes="cmd_openRemote"/>
+      <menuitem accesskey="&fileopen.accesskey;"            key="openeditorkb"       observes="cmd_open" label="&openFileCmd.label;"/>
+      <menu id="menu_RecentFiles" accesskey="&filerecentmenu.accesskey;" label="&fileRecentMenu.label;"
+            onpopupshowing="BuildRecentPagesMenu();">
+        <menupopup id="menupopup_RecentFiles" oncommand="editPage(event.target.getAttribute('value'), window, false);"/>
+          <!-- menuitems appended at runtime -->
+      </menu>
+      <menuitem accesskey="&fileclose.accesskey;" key="closekb" observes="cmd_close"/>
+      <menuseparator/>
+      <menuitem id="saveMenuitem" accesskey="&filesave.accesskey;" key="savekb" observes="cmd_save"/>
+      <menuitem accesskey="&filesaveas.accesskey;" observes="cmd_saveAs"/>
+      <menuitem accesskey="&filesaveandchangeencoding.accesskey;" observes="cmd_saveAndChangeEncoding"/>
+      <menuseparator/>
+      <menuitem id="publishMenuitem" accesskey="&publishcmd.accesskey;" key="publishkb" observes="cmd_publish"/>
+      <menuitem accesskey="&publishas.accesskey;" observes="cmd_publishAs"/>
+      <menuseparator/>
+      <menuitem accesskey="&filerevert.accesskey;" observes="cmd_revert"/>
+      <menuseparator/>
+      <menuitem id="fileExportToText"  accesskey="&fileexporttotext.accesskey;" observes="cmd_exportToText"/>
+      <menuitem id="previewInBrowser" label="&previewCmd.label;"  accesskey="&filepreview.accesskey;" observes="cmd_preview"/>
+      <!-- menuitem id="menu_SendPage" is merged here from mailEditorOverlay.xul,
+           where "position" is assumed to be just after 'previewInBrowser'  -->
+      <menuitem id="printSetupMenuItem" accesskey="&fileprintsetup.accesskey;" label="&printSetupCmd.label;" command="cmd_printSetup"/>
+      <menuitem id="printMenuItem" accesskey="&fileprint.accesskey;" key="printkb" observes="cmd_print" label="&printCmd.label;"/>
+      <!-- The Exit/Quit item is merged from platformGlobalOverlay.xul -->
+    </menupopup>
+  </menu>
+
+  <menu id="editMenu" label="&editMenu.label;" accesskey="&editmenu.accesskey;">
+    <menupopup id="edEditMenuPopup">
+      <!-- from utilityOverlay.xul -->
+      <menuitem id="menu_undo"/>
+      <menuitem id="menu_redo"/>
+      <menuseparator id="edEditMenuSep1" />
+      <menuitem id="menu_cut"/>
+      <menuitem id="menu_copy"/>
+      <menuitem id="menu_paste"/>
+      <menuitem id="menu_pasteNoFormatting" observes="cmd_pasteNoFormatting"/>
+
+<!-- PasteAs not implemented yet
+      <menu id="menu_pasteAs" label="&pasteAs.label;" accesskey="&pasteAs.accesskey;">
+        <menupopup onpopupshowing="InitPasteAsMenu();">
+          <menuitem id="menu_pasteText"    label="&pasteTextCmd.label;"     accesskey="&pasteText.accesskey;"/>
+          <menuitem id="menu_pasteImage"   label="&pasteImageCmd.label;"    accesskey="&pasteImage.accesskey;"/>
+          <menuseparator/>
+          <menuitem id="menu_pasteRows"    label="&pasteRowsCmd.label;"     accesskey="&pasteRows.accesskey;"/>
+          <menuitem id="menu_pasteColumns" label="&pasteColumnsCmd.label;"  accesskey="&pasteColumns.accesskey;"/>
+          <menuitem id="menu_pasteTable"                                    accesskey="&pasteTable.accesskey;"/>
+        </menupopup>
+      </menu>
+-->
+      <menuitem id="menu_delete"/>
+      <menuseparator id="edEditMenuSep2" />
+      <menuitem id="menu_selectAll"/>
+      <menuseparator id="sep_find"/>
+      <menuitem id="menu_find"           accesskey="&editfind.accesskey;"            key="findkb"         observes="cmd_find" label="&findCmd.label;"/>
+      <menuitem id="menu_findnext"       accesskey="&editfindnext.accesskey;"        key="findnextkb"     observes="cmd_findNext"/>
+      <menuitem id="menu_findprev"       accesskey="&editfindprev.accesskey;"        key="findprevkb"     observes="cmd_findPrev"/>
+      <menuseparator id="sep_checkspelling"/>
+      <menuitem id="menu_checkspelling" accesskey="&editcheckspelling.accesskey;"
+                key="checkspellingkb"   observes="cmd_spelling" disabled="true"
+                label="&checkSpellingCmd.label;"/>
+      <menuitem id="menu_inlinespellcheck" type="checkbox"
+                label="&enableInlineSpellChecker.label;"
+                accesskey="&enableInlineSpellChecker.accesskey;"
+                oncommand="InlineSpellCheckerUI.enabled = !InlineSpellCheckerUI.enabled"/>
+      <menuseparator id="menu_prefsSep"/>
+      <menuitem id="menu_preferences"     observes="cmd_preferences"/>
+      <!-- Note: other Edit items (menu_validate, menu_publishSettings) are inserted from composerOverlay.xul -->
+    </menupopup>
+  </menu>
+
+  <menuitem id="viewNormalMode"   type="radio" group="mode" accesskey="&NormalMode.accesskey;"     observes="cmd_NormalMode"/>
+  <menuitem id="viewAllTagsMode"  type="radio" group="mode" accesskey="&AllTagsMode.accesskey;"    observes="cmd_AllTagsMode"/>
+  <menuitem id="viewSourceMode"   type="radio" group="mode" accesskey="&HTMLSourceMode.accesskey;" observes="cmd_HTMLSourceMode" label="&HTMLSourceMode.label;"/>
+  <menuitem id="viewPreviewMode"  type="radio" group="mode" accesskey="&PreviewMode.accesskey;"    observes="cmd_PreviewMode"/>
+
+  <menupopup id = "composerCharsetMenuPopup"  onpopupshowing="updateCharsetPopupMenu(this)" />
+
+  <!-- Insert menu -->
+  <menu id="insertMenu" label="&insertMenu.label;" accesskey="&insertmenu.accesskey;">
+    <menupopup id="insertMenuPopup">
+      <menuitem id="insertImage" accesskey="&insertimage.accesskey;"      observes="cmd_image"       label="&insertImageCmd.label;"/>
+      <menuitem id="insertTable" accesskey="&inserttable.accesskey;"      observes="cmd_InsertTable" label="&insertTableCmd.label;"/>
+      <menuitem id="insertLink" accesskey="&insertlink.accesskey;"       observes="cmd_link"        label="&insertLinkCmd.label;"   key="insertlinkkb"/>
+      <menuitem id="insertAnchor" accesskey="&insertanchor.accesskey;"     observes="cmd_anchor"      label="&insertAnchorCmd.label;"/>
+      <menuitem id="insertHline" accesskey="&inserthline.accesskey;"      observes="cmd_hline"       label="&insertHLineCmd.label;"/>
+      <menuitem id="insertHTMLSource" accesskey="&insertHTMLCmd.accesskey;"   observes="cmd_insertHTMLWithDialog"  key="inserthtmlkb"/>
+      <menuitem accesskey="&insertchars.accesskey;"      observes="cmd_insertChars" id="insertChars"/>
+      <menu id="insertTOC" label="&tocMenu.label;" accesskey="&tocMenu.accesskey;">
+        <menupopup onpopupshowing="InitTOCMenu()">
+          <menuitem id="insertTOCMenuitem"
+                    label="&insertTOC.label;"
+                    accesskey="&insertTOC.accesskey;"
+                    oncommand="UpdateTOC()"/>
+          <menuitem id="updateTOCMenuitem"
+                    label="&updateTOC.label;"
+                    accesskey="&updateTOC.accesskey;"
+                    oncommand="UpdateTOC()"/>
+          <menuitem id="removeTOCMenuitem"
+                    label="&removeTOC.label;"
+                    accesskey="&removeTOC.accesskey;"
+                    oncommand="RemoveTOC()"/>
+        </menupopup>
+      </menu>
+      <menuseparator id="insertMenuSeparator"/>
+<!-- Activate this after Enter key inserts P tag and not BR
+      <menuitem accesskey="&insertbreak.accesskey;"      observes="cmd_insertBreak"      label="&insertBreakCmd.label;"/>
+-->
+      <menuitem id="insertBreakAll" accesskey="&insertbreakall.accesskey;"   observes="cmd_insertBreakAll"   label="&insertBreakAllCmd.label;"/>
+    </menupopup>
+  </menu>
+    
+  <!-- Insert menu for PlainText editor -->
+  <menu id="insertMenuPlainText" label="&insertMenu.label;" accesskey="&insertmenu.accesskey;">
+    <menupopup>
+      <menuitem accesskey="&insertchars.accesskey;" observes="cmd_insertChars" />
+    </menupopup>
+  </menu>
+
+  <!-- Format Menu -->
+  <menupopup id="formatMenuPopup" onpopupshowing="EditorInitFormatMenu()">
+    <!-- Font face submenu -->
+    <menu id="fontFaceMenu" label="&fontfaceMenu.label;" accesskey="&formatfontmenu.accesskey;" 
+          position="1">
+      <menupopup oncommand="if (event.target.localName == 'menuitem')
+                              doStatefulCommand('cmd_fontFace', event.target.getAttribute('value'));"
+                 onpopupshowing="initFontFaceMenu(this);">
+        <menuitem label="&fontVarWidth.label;"      accesskey="&fontvarwidth.accesskey;"    value=""    type="radio" name="1" observes="cmd_renderedHTMLEnabler"/>
+        <menuitem label="&fontFixedWidth.label;"    accesskey="&fontfixedwidth.accesskey;"  value="tt"  type="radio" name="1" observes="cmd_renderedHTMLEnabler"/>
+        <menuseparator/>
+        <menuitem label="&fontHelveticaFont.label;" accesskey="&fonthelvetica.accesskey;"   value="Helvetica, Arial, sans-serif"    type="radio" name="2" observes="cmd_renderedHTMLEnabler"/>
+        <menuitem label="&fontTimes.label;"         accesskey="&fonttimes.accesskey;"       value="Times New Roman, Times, serif"   type="radio" name="2" observes="cmd_renderedHTMLEnabler"/>
+        <menuitem label="&fontCourier.label;"       accesskey="&fontcourier.accesskey;"     value="Courier New, Courier, monospace" type="radio" name="2" observes="cmd_renderedHTMLEnabler"/>
+        <menuseparator/>
+          <!-- Local font face items added here by initLocalFontFaceMenu() -->
+      </menupopup>
+    </menu>
+
+    <!-- Font size submenu -->
+    <menu id="fontSizeMenu" label="&fontsizeMenu.label;"
+          accesskey="&formatsizemenu.accesskey;" 
+          position="2">
+      <menupopup onpopupshowing="initFontSizeMenu(this)">
+      <menuitem label="&decreaseFontSize.label;" accesskey="&decreasefontsize.accesskey;" observes="cmd_decreaseFont" type="radio" name="1" key="decreasefontsizekb"/>
+      <menuitem label="&increaseFontSize.label;" accesskey="&increasefontsize.accesskey;" observes="cmd_increaseFont" type="radio" name="1" key="increasefontsizekb"/>
+        <menuseparator/>
+<!-- Not supported in current font size implementation
+        <menuitem label="&size-xx-smallCmd.label;" accesskey="&size-xx-small.accesskey;" oncommand="EditorSetFontSize('xx-small')" type="radio" name="2" />
+-->
+        <menuitem label="&size-x-smallCmd.label;"  accesskey="&size-x-small.accesskey;"  oncommand="EditorSetFontSize('x-small')"  type="radio" name="2" observes="cmd_renderedHTMLEnabler"/>
+        <menuitem label="&size-smallCmd.label;"    accesskey="&size-small.accesskey;"    oncommand="EditorSetFontSize('small')"    type="radio" name="2" observes="cmd_renderedHTMLEnabler"/>
+        <menuitem label="&size-mediumCmd.label;"   accesskey="&size-medium.accesskey;"   oncommand="EditorSetFontSize('medium')"   type="radio" name="2" observes="cmd_renderedHTMLEnabler"/>
+        <menuitem label="&size-largeCmd.label;"    accesskey="&size-large.accesskey;"    oncommand="EditorSetFontSize('large')"    type="radio" name="2" observes="cmd_renderedHTMLEnabler"/>
+        <menuitem label="&size-x-largeCmd.label;"  accesskey="&size-x-large.accesskey;"  oncommand="EditorSetFontSize('x-large')"  type="radio" name="2" observes="cmd_renderedHTMLEnabler"/>
+        <menuitem label="&size-xx-largeCmd.label;" accesskey="&size-xx-large.accesskey;" oncommand="EditorSetFontSize('xx-large')" type="radio" name="2" observes="cmd_renderedHTMLEnabler"/>
+      </menupopup>
+    </menu>
+
+    <!-- Font style submenu -->
+    <menu id="fontStyleMenu" label="&fontStyleMenu.label;" 
+          accesskey="&formatstylemenu.accesskey;"
+          position="3">
+    <menupopup onpopupshowing="initFontStyleMenu(this)">
+      <menuitem label="&styleBoldCmd.label;"        accesskey="&stylebold.accesskey;"         observes="cmd_bold"          type="checkbox" key="boldkb"/>
+      <menuitem label="&styleItalicCmd.label;"      accesskey="&styleitalic.accesskey;"       observes="cmd_italic"        type="checkbox" key="italickb" />
+      <menuitem label="&styleUnderlineCmd.label;"   accesskey="&styleunderline.accesskey;"    observes="cmd_underline"     type="checkbox" key="underlinekb"/>
+      <menuitem label="&styleStrikeThruCmd.label;"  accesskey="&stylestrikethru.accesskey;"   observes="cmd_strikethrough" type="checkbox"/>
+      <menuitem label="&styleSuperscriptCmd.label;" accesskey="&stylesuperscript.accesskey;"  observes="cmd_superscript"   type="checkbox"/>
+      <menuitem label="&styleSubscriptCmd.label;"   accesskey="&stylesubscript.accesskey;"    observes="cmd_subscript"     type="checkbox"/>
+      <menuitem label="&fontFixedWidth.label;"      accesskey="&fontfixedwidth.accesskey;"    observes="cmd_tt"            type="checkbox" key="fixedwidthkb"/>
+      <menuitem label="&styleNonbreakingCmd.label;" accesskey="&stylenonbreaking.accesskey;"  observes="cmd_nobreak"       type="checkbox"/>
+      <menuseparator/>
+      <menuitem label="&styleEm.label;"             accesskey="&styleEm.accesskey;"           observes="cmd_em"            type="checkbox"/>
+      <menuitem label="&styleStrong.label;"         accesskey="&styleStrong.accesskey;"       observes="cmd_strong"        type="checkbox"/>
+      <menuitem label="&styleCite.label;"           accesskey="&styleCite.accesskey;"         observes="cmd_cite"          type="checkbox"/>
+      <menuitem label="&styleAbbr.label;"           accesskey="&styleAbbr.accesskey;"         observes="cmd_abbr"          type="checkbox"/>
+      <menuitem label="&styleAcronym.label;"        accesskey="&styleAcronym.accesskey;"      observes="cmd_acronym"       type="checkbox"/>
+      <menuitem label="&styleCode.label;"           accesskey="&styleCode.accesskey;"         observes="cmd_code"          type="checkbox"/>
+      <menuitem label="&styleSamp.label;"           accesskey="&styleSamp.accesskey;"         observes="cmd_samp"          type="checkbox"/>
+      <menuitem label="&styleVar.label;"            accesskey="&styleVar.accesskey;"          observes="cmd_var"           type="checkbox"/>
+    </menupopup>
+    </menu>
+    
+    <!-- Note: "cmd_fontColor" only monitors color state, it doesn't execute the command
+         (We should use "cmd_fontColorState" and "cmd_backgroundColorState" ?) -->
+    <menuitem id="fontColor" label="&formatFontColor.label;" 
+          accesskey="&formatfontcolor.accesskey;"
+          observes="cmd_fontColor"
+          oncommand="EditorSelectColor('Text', null);"
+          position="4"/>
+    <menuseparator id="removeSep" position="5"/>
+
+    <!-- label and accesskey set at runtime from strings -->
+    <menuitem id="removeStylesMenuitem" key="removestyleskb"
+          observes="cmd_removeStyles"
+          position="6"/>
+    <menuitem id="removeLinksMenuitem" key="removelinkskb"
+          observes="cmd_removeLinks"
+          position="7"/>
+    <menuitem id="removeNamedAnchorsMenuitem"  label="&formatRemoveNamedAnchors.label;"
+          key="removenamedanchorskb"
+          accesskey="&formatRemoveNamedAnchors.accesskey;"
+          observes="cmd_removeNamedAnchors"
+          position="8"/>
+    <menuseparator id="tabSep" position="9"/>
+
+    <!-- Note: the 'Init' menu methods for Paragraph, List, and Align
+         assume that the id = 'menu_'+tagName (the 'value' label),
+         except for the first ('none') item
+     -->
+    <!-- Paragraph Style submenu -->
+    <menu id="paragraphMenu" label="&paragraphMenu.label;"
+          accesskey="&formatparagraphmenu.accesskey;"
+          position="10" onpopupshowing="InitParagraphMenu()">
+      <menupopup oncommand="doStatefulCommand('cmd_paragraphState', event.target.getAttribute('value'))">
+        <menuitem id="menu_bodyText"  type="radio" name="1" label="&bodyTextCmd.label;"             accesskey="&bodytext.accesskey;"            value=""      observes="cmd_renderedHTMLEnabler"/>
+        <menuitem id="menu_p"         type="radio" name="1" label="&paragraphParagraphCmd.label;"   accesskey="&paragraphparagraph.accesskey;"  value="p"     observes="cmd_renderedHTMLEnabler"/>
+        <menuitem id="menu_h1"        type="radio" name="1" label="&heading1Cmd.label;"             accesskey="&heading1.accesskey;"            value="h1"    observes="cmd_renderedHTMLEnabler"/>
+        <menuitem id="menu_h2"        type="radio" name="1" label="&heading2Cmd.label;"             accesskey="&heading2.accesskey;"            value="h2"    observes="cmd_renderedHTMLEnabler"/>
+        <menuitem id="menu_h3"        type="radio" name="1" label="&heading3Cmd.label;"             accesskey="&heading3.accesskey;"            value="h3"    observes="cmd_renderedHTMLEnabler"/>
+        <menuitem id="menu_h4"        type="radio" name="1" label="&heading4Cmd.label;"             accesskey="&heading4.accesskey;"            value="h4"    observes="cmd_renderedHTMLEnabler"/>
+        <menuitem id="menu_h5"        type="radio" name="1" label="&heading5Cmd.label;"             accesskey="&heading5.accesskey;"            value="h5"    observes="cmd_renderedHTMLEnabler"/>
+        <menuitem id="menu_h6"        type="radio" name="1" label="&heading6Cmd.label;"             accesskey="&heading6.accesskey;"            value="h6"    observes="cmd_renderedHTMLEnabler"/>
+        <menuitem id="menu_address"   type="radio" name="1" label="&paragraphAddressCmd.label;"     accesskey="&paragraphaddress.accesskey;"    value="address"  observes="cmd_renderedHTMLEnabler"/>   
+        <menuitem id="menu_pre"       type="radio" name="1" label="&paragraphPreformatCmd.label;"   accesskey="&paragraphpreformat.accesskey;"  value="pre"   observes="cmd_renderedHTMLEnabler"/>       
+      </menupopup>
+    </menu>
+
+    <!-- List Style submenu -->
+    <menu id="listMenu" label="&formatlistMenu.label;"
+          accesskey="&formatlistmenu.accesskey;"
+          position="11" onpopupshowing="InitListMenu()">
+      <menupopup>
+        <menuitem id="menu_noList" type="radio" name="1" label="&noneCmd.label;"           accesskey="&none.accesskey;"           observes="cmd_removeList"/>
+        <menuitem id="menu_ul"     type="radio" name="1" label="&listBulletCmd.label;"     accesskey="&listbullet.accesskey;"     observes="cmd_ul"/>
+        <menuitem id="menu_ol"     type="radio" name="1" label="&listNumberedCmd.label;"   accesskey="&listnumbered.accesskey;"   observes="cmd_ol"/>
+        <menuitem id="menu_dt"     type="radio" name="1" label="&listTermCmd.label;"       accesskey="&listterm.accesskey;"       observes="cmd_dt"/>
+        <menuitem id="menu_dd"     type="radio" name="1" label="&listDefinitionCmd.label;" accesskey="&listdefinition.accesskey;" observes="cmd_dd"/>
+        <menuseparator/>
+        <menuitem id="listProps" label="&listProps.label;" accesskey="&listprops.accesskey;" observes="cmd_listProperties"/>
+      </menupopup>
+    </menu>
+    <menuseparator id="identingSep" position="12"/>
+
+    <menuitem id="increaseIndent" label="&increaseIndent.label;"  accesskey="&increaseindent.accesskey;"  key="increaseindentkb"
+                observes="cmd_indent" position="13"/>
+    <menuitem id="decreaseIndent" label="&decreaseIndent.label;"  accesskey="&decreaseindent.accesskey;"  key="decreaseindentkb"
+              observes="cmd_outdent"  position="14"/>
+
+    <menu id="alignMenu" label="&alignMenu.label;" accesskey="&formatalignmenu.accesskey;"
+        onpopupshowing="InitAlignMenu()"
+        position="15">
+      <!-- Align submenu -->
+      <menupopup oncommand="doStatefulCommand('cmd_align', event.target.getAttribute('value'))">
+        <menuitem id="menu_left"    label="&alignLeft.label;"  accesskey="&alignleft.accesskey;"      type="radio" name="1" value="left"    observes="cmd_renderedHTMLEnabler"/>
+        <menuitem id="menu_center"  label="&alignCenter.label;"  accesskey="&aligncenter.accesskey;"  type="radio" name="1" value="center"  observes="cmd_renderedHTMLEnabler"/>
+        <menuitem id="menu_right"   label="&alignRight.label;"   accesskey="&alignright.accesskey;"   type="radio" name="1" value="right"   observes="cmd_renderedHTMLEnabler"/>
+        <menuitem id="menu_justify" label="&alignJustify.label;" accesskey="&alignjustify.accesskey;" type="radio" name="1" value="justify" observes="cmd_renderedHTMLEnabler"/>
+      </menupopup>
+    </menu>
+    <menuseparator id="tableSep" position="16"/>
+    <!-- Merge Table Menu and separator in Messenger Composer here -->
+    <!-- Merge property items here -->
+  </menupopup>
+
+  <menuitem id="snapToGrid" label="&grid.label;" accesskey="&grid.accesskey;"
+            oncommand="goDoCommand('cmd_grid')"   observes="cmd_renderedHTMLEnabler"/>
+
+  <!-- Next 3 are items to append at the bottom of the formatMenuPopup -->
+  <!-- label and accesskey filled in during menu creation -->
+  <menuitem id="objectProperties"   oncommand="goDoCommand('cmd_objectProperties')"   observes="cmd_renderedHTMLEnabler"/>
+  <!-- Don't use 'observes', must call command correctly -->
+  <menuitem id="pageProperties"       label="&pageProperties.label;"       accesskey="&pageproperties.accesskey;"      
+            oncommand="goDoCommand('cmd_pageProperties')"  observes="cmd_renderedHTMLEnabler"/>
+  <menuitem id="colorsAndBackground"  label="&colorsAndBackground.label;"  accesskey="&colorsandbackground.accesskey;"
+            oncommand="goDoCommand('cmd_colorProperties')" observes="cmd_renderedHTMLEnabler"/>
+
+  <menu id="tableMenu" label="&tableMenu.label;" accesskey="&tablemenu.accesskey;">
+    <menupopup  onpopupshowing="EditorInitTableMenu()">
+      <!-- From EditorCommandOverlay.xul (shared with context popup) -->
+      <menu id="tableInsertMenu" label="&tableInsertMenu.label;" accesskey="&tableinsertmenu.accesskey;">
+        <menupopup>
+          <menuitem label="&insertTableCmd.label;"    accesskey="&tabletable.accesskey;"        observes="cmd_InsertTable"/>
+          <menuseparator />
+          <menuitem label="&tableRowAbove.label;"     accesskey="&tablerow.accesskey;"          observes="cmd_InsertRowAbove"/>
+          <menuitem label="&tableRowBelow.label;"     accesskey="&tablerowbelow.accesskey;"     observes="cmd_InsertRowBelow"/>
+          <menuseparator />
+          <menuitem label="&tableColumnBefore.label;" accesskey="&tablecolumn.accesskey;"       observes="cmd_InsertColumnBefore"/>
+          <menuitem label="&tableColumnAfter.label;"  accesskey="&tablecolumnafter.accesskey;"  observes="cmd_InsertColumnAfter"/>
+          <menuseparator />
+          <menuitem label="&tableCellBefore.label;"   accesskey="&tablecell.accesskey;"         observes="cmd_InsertCellBefore"/>
+          <menuitem label="&tableCellAfter.label;"    accesskey="&tablecellafter.accesskey;"    observes="cmd_InsertCellAfter"/>
+        </menupopup>
+      </menu>
+      <menu id="tableSelectMenu" label="&tableSelectMenu.label;" accesskey="&tableselectmenu.accesskey;">
+        <menupopup id="tableSelectPopup">
+          <menuitem id="menu_SelectTable"    label="&tableTable.label;"    accesskey="&tabletable.accesskey;"    observes="cmd_SelectTable"    />
+          <menuitem id="menu_SelectRow"      label="&tableRow.label;"      accesskey="&tablerow.accesskey;"      observes="cmd_SelectRow"      />
+          <menuitem id="menu_SelectColumn"   label="&tableColumn.label;"   accesskey="&tablecolumn.accesskey;"   observes="cmd_SelectColumn"   />
+          <menuitem id="menu_SelectCell"     label="&tableCell.label;"     accesskey="&tablecell.accesskey;"     observes="cmd_SelectCell"     />
+          <menuitem id="menu_SelectAllCells" label="&tableAllCells.label;" accesskey="&tableallcells.accesskey;" observes="cmd_SelectAllCells" />
+        </menupopup>
+      </menu>
+      <menu id="tableDeleteMenu" label="&tableDeleteMenu.label;" accesskey="&tabledeletemenu.accesskey;">
+        <menupopup id="tableDeletePopup">
+          <menuitem id="menu_DeleteTable"         label="&tableTable.label;"        accesskey="&tabletable.accesskey;"          observes="cmd_DeleteTable"/>
+          <menuitem id="menu_DeleteRow"           label="&tableRows.label;"         accesskey="&tablerow.accesskey;"            observes="cmd_DeleteRow"/>
+          <menuitem id="menu_DeleteColumn"        label="&tableColumns.label;"      accesskey="&tablecolumn.accesskey;"         observes="cmd_DeleteColumn"/>
+          <menuitem id="menu_DeleteCell"          label="&tableCells.label;"        accesskey="&tablecell.accesskey;"           observes="cmd_DeleteCell"/>
+          <menuitem id="menu_DeleteCellContents"  label="&tableCellContents.label;" accesskey="&tablecellcontents.accesskey;"   observes="cmd_DeleteCellContents"/>
+        </menupopup>
+      </menu>
+      <menuseparator />
+      <!-- menu label is set in InitTableMenu -->
+      <menuitem id="menu_JoinTableCells"   label="&tableJoinCells.label;"   accesskey="&tablejoincells.accesskey;"   observes="cmd_JoinTableCells"/>
+      <menuitem id="menu_SlitTableCell"    label="&tableSplitCell.label;"   accesskey="&tablesplitcell.accesskey;"   observes="cmd_SplitTableCell"/>
+      <menuitem id="menu_ConvertToTable"   label="&convertToTable.label;"   accesskey="&converttotable.accesskey;"   observes="cmd_ConvertToTable"/>
+      <menuseparator />
+      <menuitem id="menu_TableOrCellColor" label="&tableOrCellColor.label;" accesskey="&tableOrCellColor.accesskey;" observes="cmd_TableOrCellColor"/>
+      <menuitem id="menu_tableProperties"  label="&tableProperties.label;"  accesskey="&tableProperties.accesskey;"  observes="cmd_editTable"/>
+    </menupopup>
+  </menu>
+
+  <!-- this is only used in messengercompose.xul -->
+  <toolbarbutton type="menu" id="AlignPopupButton" observes="cmd_align"
+              tooltiptext="&AlignPopupButton.tooltip;">
+    <menupopup id="AlignPopup">
+      <menuitem id="AlignLeftItem" class="menuitem-iconic" label="&alignLeft.label;"
+                oncommand="doStatefulCommand('cmd_align', 'left')"
+                tooltiptext="&alignLeftButton.tooltip;"    />
+      <menuitem id="AlignCenterItem" class="menuitem-iconic" label="&alignCenter.label;"
+                oncommand="doStatefulCommand('cmd_align', 'center')"
+                tooltiptext="&alignCenterButton.tooltip;"  />
+      <menuitem id="AlignRightItem" class="menuitem-iconic" label="&alignRight.label;"
+                oncommand="doStatefulCommand('cmd_align', 'right')"
+                tooltiptext="&alignRightButton.tooltip;"   />
+      <menuitem id="AlignJustifyItem" class="menuitem-iconic" label="&alignJustify.label;"
+                oncommand="doStatefulCommand('cmd_align', 'justify')"
+                tooltiptext="&alignjustifyButton.tooltip;" />
+    </menupopup>
+  </toolbarbutton>
+
+  <!-- InsertPopupButton is used by messengercompose.xul -->
+  <toolbarbutton type="menu" id="InsertPopupButton" observes="cmd_renderedHTMLEnabler"
+              tooltiptext="&InsertPopupButton.tooltip;">
+    <menupopup id="InsertPopup">
+      <menuitem id="InsertLinkItem" class="menuitem-iconic" observes="cmd_link"
+                oncommand="goDoCommand('cmd_link')" label="&linkToolbarCmd.label;"
+                tooltiptext="&linkToolbarCmd.tooltip;"   />
+      <menuitem id="InsertAnchorItem" class="menuitem-iconic" observes="cmd_anchor"
+                oncommand="goDoCommand('cmd_anchor')" label="&anchorToolbarCmd.label;"
+                tooltiptext="&anchorToolbarCmd.tooltip;" />
+      <menuitem id="InsertImageItem"  class="menuitem-iconic" observes="cmd_image"
+                oncommand="goDoCommand('cmd_image')" label="&imageToolbarCmd.label;"
+                tooltiptext="&imageToolbarCmd.tooltip;"  />
+      <menuitem id="InsertHRuleItem"  class="menuitem-iconic" observes="cmd_hline"
+                oncommand="goDoCommand('cmd_hline')" label="&hruleToolbarCmd.label;"
+                tooltiptext="&hruleToolbarCmd.tooltip;"  />
+      <menuitem id="InsertTableItem"  class="menuitem-iconic" observes="cmd_table"
+                oncommand="goDoCommand('cmd_table')" label="&tableToolbarCmd.label;"
+                tooltiptext="&tableToolbarCmd.tooltip;"  />
+    </menupopup>
+  </toolbarbutton>
+
+  <!-- Editor toolbar items -->
+  <!-- note that we override the submenu item label "Blank Window" with "New" used for the menu -->
+  <toolbarbutton id="newButton" class="toolbarbutton-1"
+                 label="&newMenu.label;" command="cmd_newEditor"
+                 tooltiptext="&newToolbarCmd.tooltip;"/>
+  <toolbarbutton id="openButton" class="toolbarbutton-1"
+                 label="&openToolbarCmd.label;" observes="cmd_open"
+                 tooltiptext="&openToolbarCmd.tooltip;"/>
+  <toolbarbutton id="saveButton" class="toolbarbutton-1" observes="cmd_save"
+                 tooltiptext="&saveToolbarCmd.tooltip;"/>
+  <toolbarbutton id="publishButton" class="toolbarbutton-1"
+                 observes="cmd_publish"
+                 tooltiptext="&publishToolbarCmd.tooltip;"/>
+  <toolbarbutton id="previewButton" class="toolbarbutton-1"
+                 label="&previewToolbarCmd.label;" observes="cmd_preview"
+                 tooltiptext="&previewToolbarCmd.tooltip;"/>
+  <toolbarbutton id="cutButton" class="toolbarbutton-1"
+                 label="&cutCmd.label;" command="cmd_cut"
+                 tooltiptext="&cutCmd.label;"/>
+  <toolbarbutton id="copyButton" class="toolbarbutton-1"
+                 label="&copyCmd.label;" command="cmd_copy"
+                 tooltiptext="&copyCmd.label;"/>
+  <toolbarbutton id="pasteButton" class="toolbarbutton-1"
+                 label="&pasteCmd.label;" command="cmd_paste"
+                 tooltiptext="&pasteCmd.label;"/>
+
+  <toolbarbutton id="printButton" type="menu-button" class="toolbarbutton-1"
+                 label="&printToolbarCmd.label;"
+                 tooltiptext="&printToolbarCmd.tooltip;"
+                 oncommand="if (event.target==this) goDoCommand('cmd_print');">
+    <menupopup id="printMenu">
+      <menuitem id="printMenuItemToolbar" accesskey="&fileprint.accesskey;" label="&printCmd.label;" default="true"
+                oncommand="goDoCommand('cmd_print');"/>
+      <!-- 'printSetupToolbar' is merged in here from platformGlobalOverlay.xul -->
+    </menupopup>
+  </toolbarbutton>
+    
+  <toolbarbutton id="findButton" class="toolbarbutton-1"
+                 label="&findToolbarCmd.label;" observes="cmd_find"
+                 tooltiptext="&findToolbarCmd.tooltip;"/>
+  <toolbarbutton id="spellingButton" class="toolbarbutton-1" disabled="true"
+                 label="&spellToolbarCmd.label;" observes="cmd_spelling"
+                 tooltiptext="&spellToolbarCmd.tooltip;"/>
+  <toolbarbutton id="imageButton" class="toolbarbutton-1"
+                 label="&imageToolbarCmd.label;" observes="cmd_image"
+                 tooltiptext="&imageToolbarCmd.tooltip;"/>
+  <toolbarbutton id="hlineButton" class="toolbarbutton-1"
+                 label="&hruleToolbarCmd.label;" observes="cmd_hline"
+                 tooltiptext="&hruleToolbarCmd.tooltip;"/>
+  <toolbarbutton id="tableButton" class="toolbarbutton-1"
+                 label="&tableToolbarCmd.label;" observes="cmd_table"
+                 tooltiptext="&tableToolbarCmd.tooltip;"/>
+  <toolbarbutton id="linkButton" class="toolbarbutton-1"
+                 label="&linkToolbarCmd.label;" observes="cmd_link"
+                 tooltiptext="&linkToolbarCmd.tooltip;"/>
+  <toolbarbutton id="namedAnchorButton" class="toolbarbutton-1"
+                 label="&anchorToolbarCmd.label;" observes="cmd_anchor"
+                 tooltiptext="&anchorToolbarCmd.tooltip;"/>
+
+  <!-- Formatting toolbar items. "value" are HTML tagnames, don't translate -->
+  <menulist class="toolbar-focustarget" id="ParagraphSelect" observes="cmd_renderedHTMLEnabler"
+    tooltiptext="&ParagraphSelect.tooltip;" crop="right">
+    <observes element="cmd_paragraphState" attribute="state" onbroadcast="onParagraphFormatChange(this.parentNode, 'cmd_paragraphState')"/>
+    <menupopup id="ParagraphPopup" oncommand="doStatefulCommand('cmd_paragraphState', event.target.value)">
+      <menuitem label="&bodyTextCmd.label;"            value=""/>
+      <menuitem label="&paragraphParagraphCmd.label;"  value="p"/>
+      <menuitem label="&heading1Cmd.label;"            value="h1"/>
+      <menuitem label="&heading2Cmd.label;"            value="h2"/>
+      <menuitem label="&heading3Cmd.label;"            value="h3"/>
+      <menuitem label="&heading4Cmd.label;"            value="h4"/>
+      <menuitem label="&heading5Cmd.label;"            value="h5"/>
+      <menuitem label="&heading6Cmd.label;"            value="h6"/>
+      <menuitem label="&paragraphAddressCmd.label;"    value="address"/>
+      <menuitem label="&paragraphPreformatCmd.label;"  value="pre"/>
+    </menupopup>
+  </menulist>
+
+  <!-- "value" are HTML tagnames, don't translate -->
+  <menulist class="toolbar-focustarget" id="FontFaceSelect" observes="cmd_renderedHTMLEnabler"
+    tooltiptext="&FontFaceSelect.tooltip;" crop="right">
+    <observes element="cmd_fontFace" attribute="state" onbroadcast="onFontFaceChange(this.parentNode, 'cmd_fontFace')"/>
+    <menupopup id="FontFacePopup" oncommand="doStatefulCommand('cmd_fontFace', event.target.value)">
+      <menuitem label="&fontVarWidth.label;"      value=""/>
+      <menuitem label="&fontFixedWidth.label;"    value="tt"/>
+      <menuseparator/>
+      <menuitem label="&fontHelveticaFont.label;" value="Helvetica, Arial, sans-serif"/>
+      <menuitem label="&fontTimes.label;"         value="Times New Roman, Times, serif"/>
+      <menuitem label="&fontCourier.label;"       value="Courier New, Courier, monospace"/>
+      <menuseparator/>
+    </menupopup>
+  </menulist>  
+  
+  <menulist class="toolbar-focustarget" id="FontSizeSelect" oncommand="EditorSelectFontSize()"  tooltiptext="&FontSizeSelect.tooltip;" crop="right">
+    <observes element="cmd_fontSize" attribute="state" onbroadcast="onFontSizeChange(this.parentNode, 'cmd_fontSize')"/>
+    <menupopup>
+      <menuitem label="&size-xx-smallCmd.label;"/>
+      <menuitem label="&size-x-smallCmd.label;"/>
+      <menuitem label="&size-smallCmd.label;"/>
+      <menuitem label="&size-mediumCmd.label;"/>
+      <menuitem label="&size-largeCmd.label;"/>
+      <menuitem label="&size-x-largeCmd.label;"/>
+      <menuitem label="&size-xx-largeCmd.label;"/>
+    </menupopup>
+  </menulist>          
+
+  <stack id="ColorButtons" align="center">
+    <observes element="cmd_fontColor"       attribute="state" onbroadcast="onFontColorChange()"/>
+    <observes element="cmd_backgroundColor" attribute="state" onbroadcast="onBackgroundColorChange()"/>
+    <box class="color-button" id="BackgroundColorButton"
+          onclick="EditorSelectColor('', event);"
+          tooltiptext="&BackgroundColorButton.tooltip;"/>
+    <box class="color-button" id="TextColorButton"
+          onclick="EditorSelectColor('Text', event);"
+          tooltiptext="&TextColorButton.tooltip;"/>
+  </stack>
+  <toolbarbutton id="HighlightColorButton"
+          tooltiptext="&HighlightColorButton.tooltip;" command="cmd_highlight">
+    <observes element="cmd_highlight" attribute="state" onbroadcast="onHighlightColorChange()"/>
+    <observes element="cmd_highlight" attribute="collapsed"/>
+  </toolbarbutton>
+
+<!-- A BUG IN CSS/BOXES MAKES THIS ASSERT WHEN CLASS= IS PRESENT AND WE TRY TO COLLAPSE THE TOOLBOX -->
+  <toolbarbutton id="DecreaseFontSizeButton" observes="cmd_decreaseFont"
+          tooltiptext="&decreaseFontSizeToolbarCmd.tooltip;"/>
+  <toolbarbutton id="IncreaseFontSizeButton" observes="cmd_increaseFont"
+          tooltiptext="&increaseFontSizeToolbarCmd.tooltip;"/>
+
+  <toolbarbutton id="boldButton" type="checkbox" autoCheck="false" observes="cmd_bold"
+          tooltiptext="&boldToolbarCmd.tooltip;">
+    <observes element="cmd_bold" type="checkbox" attribute="state" onbroadcast="onButtonUpdate(this.parentNode, 'cmd_bold')"/>
+  </toolbarbutton>
+  <toolbarbutton id="italicButton" type="checkbox" autoCheck="false" observes="cmd_italic"
+          tooltiptext="&italicToolbarCmd.tooltip;">
+    <observes element="cmd_italic" attribute="state" onbroadcast="onButtonUpdate(this.parentNode, 'cmd_italic')"/>
+  </toolbarbutton>
+  <toolbarbutton id="underlineButton" type="checkbox" autoCheck="false" observes="cmd_underline"
+          tooltiptext="&underlineToolbarCmd.tooltip;">
+    <observes element="cmd_underline" attribute="state" onbroadcast="onButtonUpdate(this.parentNode, 'cmd_underline')"/>
+  </toolbarbutton>
+
+  <toolbarbutton id="ulButton" type="radio" group="lists" autoCheck="false" observes="cmd_ul"
+          tooltiptext="&bulletListToolbarCmd.tooltip;">
+      <observes element="cmd_ul" attribute="state" onbroadcast="onButtonUpdate(this.parentNode, 'cmd_ul')"/>
+  </toolbarbutton>
+
+  <toolbarbutton id="olButton" type="radio" group="lists" autoCheck="false" observes="cmd_ol"
+          tooltiptext="&numberListToolbarCmd.tooltip;">
+      <observes element="cmd_ol" attribute="state" onbroadcast="onButtonUpdate(this.parentNode, 'cmd_ol')"/>
+  </toolbarbutton>
+
+  <toolbarbutton id="outdentButton" observes="cmd_outdent"
+          tooltiptext="&outdentToolbarCmd.tooltip;"/>
+  <toolbarbutton id="indentButton" observes="cmd_indent"
+          tooltiptext="&indentToolbarCmd.tooltip;"/>
+
+  <!-- alignment buttons -->
+  <toolbarbutton id="align-left-button" type="radio" group="align" autoCheck="false"
+                 oncommand="doStatefulCommand('cmd_align', 'left')"
+                 tooltiptext="&alignLeft.tooltip;" >
+    <observes element="cmd_align" attribute="state" 
+              onbroadcast="onStateButtonUpdate(this.parentNode, 'cmd_align', 'left')" />
+  </toolbarbutton>
+  <toolbarbutton id="align-center-button" type="radio" group="align" autoCheck="false"
+                 oncommand="doStatefulCommand('cmd_align', 'center')"
+                 tooltiptext="&alignCenter.tooltip;" >
+    <observes element="cmd_align" attribute="state" 
+              onbroadcast="onStateButtonUpdate(this.parentNode, 'cmd_align', 'center')"/>
+  </toolbarbutton>
+  <toolbarbutton id="align-right-button" type="radio" group="align" autoCheck="false"
+                 oncommand="doStatefulCommand('cmd_align', 'right')"
+                 tooltiptext="&alignRight.tooltip;" >
+    <observes element="cmd_align" attribute="state"
+              onbroadcast="onStateButtonUpdate(this.parentNode, 'cmd_align', 'right')"/>
+  </toolbarbutton>
+  <toolbarbutton id="align-justify-button" type="radio" group="align" autoCheck="false"
+                 oncommand="doStatefulCommand('cmd_align', 'justify')"
+                 tooltiptext="&alignJustify.tooltip;" >
+    <observes element="cmd_align" attribute="state"
+              onbroadcast="onStateButtonUpdate(this.parentNode, 'cmd_align', 'justify')"/>
+  </toolbarbutton>
+  
+  <toolbarbutton id="absolutePositionButton" type="checkbox" tooltiptext="&layer.tooltip;" observes="cmd_absPos">
+    <observes element="cmd_absPos" attribute="state" onbroadcast="onStateButtonUpdate(this.parentNode, 'cmd_absPos', 'absolute')"/>
+  </toolbarbutton>
+  <toolbarbutton id="decreaseZIndexButton" observes="cmd_decreaseZIndex"
+                 tooltiptext="&layerSendToBack.tooltip;"/>
+  <toolbarbutton id="increaseZIndexButton" observes="cmd_increaseZIndex"
+                 tooltiptext="&layerBringToFront.tooltip;"/>
+
+  <!-- Edit Mode toolbar -->
+  <tabs id="EditModeTabs" onselect="this.selectedItem.doCommand()"/>
+  <tab id="NormalModeButton"   class="tab-bottom edit-mode _plain" type="text" selected="1" label="&NormalModeTab.label;"  oncommand="goDoCommand('cmd_NormalMode');"
+          tooltiptext="&NormalMode.tooltip;"/>
+  <tab id="TagModeButton"      class="tab-bottom edit-mode _plain" type="text" selected="0" label="&AllTagsMode.label;"    oncommand="goDoCommand('cmd_AllTagsMode');"
+          tooltiptext="&AllTagsMode.tooltip;"/>
+  <tab id="SourceModeButton"   class="tab-bottom edit-mode _plain" type="text" selected="0" label="&SourceMode.label;"     oncommand="goDoCommand('cmd_HTMLSourceMode');"
+          tooltiptext="&HTMLSourceMode.tooltip;" dir="&SourceTabDirection;"/>
+  <tab id="PreviewModeButton"  class="tab-bottom edit-mode _plain" type="text" selected="0" label="&PreviewMode.label;"    oncommand="goDoCommand('cmd_PreviewMode');"
+          tooltiptext="&PreviewMode.tooltip;"/>
+
+  <!-- Paste as quotation is used by mail compose,
+       but in composer it has to go in the debug menu
+   -->
+  <menuitem id="menu_pasteQuote" accesskey="&editpastequotation.accesskey;" command="cmd_pasteQuote" key="pastequotationkb"/>
+
+</overlay>
new file mode 100644
--- /dev/null
+++ b/editor/ui/composer/content/editorPrefsOverlay.xul
@@ -0,0 +1,72 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE overlay [
+<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" >
+%brandDTD;
+<!ENTITY % editorPrefsOverlayDTD SYSTEM "chrome://editor/locale/editorPrefsOverlay.dtd" >
+%editorPrefsOverlayDTD;
+]>
+
+<overlay id="editorPrefsOverlay"
+         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+  <preferences id="appearance_preferences">
+    <preference id="general.startup.editor"
+                name="general.startup.editor"
+                type="bool"/>
+  </preferences>
+
+  <!-- editor startup toggle -->
+  <groupbox id="generalStartupPreferences">
+    <checkbox id="generalStartupEditor"
+              insertafter="generalStartupMail,generalStartupBrowser"
+              label="&editorCheck.label;"
+              accesskey="&editorCheck.accesskey;"
+              preference="general.startup.editor"/>
+  </groupbox>
+  <!-- category tree entries for editor -->
+  <treechildren id="prefsPanelChildren">
+    <treeitem container="true"
+              id="composerItem"
+              insertafter="mailnews,navigator"
+              label="&compose.label;"
+              prefpane="composer_pane"
+              url="chrome://editor/content/pref-composer.xul"
+              helpTopic="composer_prefs_general">
+      <treechildren id="composerChildren">
+        <treeitem id="editingItem"
+                  label="&editing.label;"
+                  prefpane="editing_pane"
+                  url="chrome://editor/content/pref-editing.xul"
+                  helpTopic="composer_prefs_newpage"/>
+        <treeitem id="toolbarsItem"
+                  label="&toolbars.label;"
+                  prefpane="toolbars_pane"
+                  url="chrome://editor/content/pref-toolbars.xul"
+                  helpTopic="composer_prefs_toolbars"/>
+      </treechildren>
+    </treeitem>
+  </treechildren>
+
+  <!-- category tree entries for editor -->
+  <treechildren id="panelChildren">
+    <treeitem container="true" id="editor" insertafter="mailnews,navigator">
+      <treerow>       
+        <treecell label="Migrated: &compose.label;"/> 
+      </treerow>
+      <treechildren>
+        <treeitem>
+          <treerow>
+            <treecell label="Migrated: &editing.label;"/> 
+          </treerow>
+        </treeitem>
+        <treeitem>
+          <treerow>
+            <treecell label="Migrated: &toolbars.label;"/> 
+          </treerow>
+        </treeitem>  
+      </treechildren>
+    </treeitem>
+  </treechildren>
+           
+</overlay>         
new file mode 100644
--- /dev/null
+++ b/editor/ui/composer/content/editorSmileyOverlay.xul
@@ -0,0 +1,139 @@
+<?xml version="1.0"?> 
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Editor Smiley Overlay.
+   -
+   - The Initial Developer of the Original Code is
+   - Neil Rashbrook.
+   - Portions created by the Initial Developer are Copyright (C) 2003
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -    Neil Rashbrook <neil@parkwaycc.co.uk>
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either the GNU General Public License Version 2 or later (the "GPL"), or
+   - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the LGPL or the GPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!DOCTYPE overlay SYSTEM "chrome://editor/locale/editorSmileyOverlay.dtd">
+
+<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <!-- smiley menu -->
+  <toolbarbutton type="menu" id="smileButtonMenu"
+                 observes="cmd_smiley"
+                 tooltiptext="&SmileButton.tooltip;">
+    <menupopup id="smilyPopup">
+      <menuitem class="smiley insert-smile menuitem-iconic"       label="&smiley1Cmd.label;" 
+                oncommand="doStatefulCommand('cmd_smiley', ':-)'  )"  
+                tooltiptext="&smiley1Cmd.tooltip;"  />
+      <menuitem class="smiley insert-frown menuitem-iconic"       label="&smiley2Cmd.label;"
+                oncommand="doStatefulCommand('cmd_smiley', ':-('  )" 
+                tooltiptext="&smiley2Cmd.tooltip;"  />                                              
+      <menuitem class="smiley insert-wink menuitem-iconic"        label="&smiley3Cmd.label;"
+                oncommand="doStatefulCommand('cmd_smiley', ';-)'  )"  
+                tooltiptext="&smiley3Cmd.tooltip;"  />                       
+      <menuitem class="smiley insert-tongue menuitem-iconic"      label="&smiley4Cmd.label;"
+                oncommand="doStatefulCommand('cmd_smiley', ':-P'  )" 
+                tooltiptext="&smiley4Cmd.tooltip;"  />
+      <menuitem class="smiley insert-laughing menuitem-iconic"    label="&smiley5Cmd.label;"
+                oncommand="doStatefulCommand('cmd_smiley', ':-D'  )" 
+                tooltiptext="&smiley5Cmd.tooltip;"  />
+      <menuitem class="smiley insert-embarrassed menuitem-iconic" label="&smiley6Cmd.label;"
+                oncommand="doStatefulCommand('cmd_smiley', ':-['  )" 
+                tooltiptext="&smiley6Cmd.tooltip;"  />
+      <menuitem class="smiley insert-undecided menuitem-iconic"   label="&smiley7Cmd.label;"
+                oncommand="doStatefulCommand('cmd_smiley', ':-\\' )" 
+                tooltiptext="&smiley7Cmd.tooltip;"  />
+      <menuitem class="smiley insert-surprise menuitem-iconic"   label="&smiley8Cmd.label;"
+                oncommand="doStatefulCommand('cmd_smiley', '=-O' )" 
+                tooltiptext="&smiley8Cmd.tooltip;"  />           
+      <menuitem class="smiley insert-kiss menuitem-iconic"   label="&smiley9Cmd.label;"
+                oncommand="doStatefulCommand('cmd_smiley', ':-*' )" 
+                tooltiptext="&smiley9Cmd.tooltip;"  />           
+      <menuitem class="smiley insert-yell menuitem-iconic"   label="&smiley10Cmd.label;"
+                oncommand="doStatefulCommand('cmd_smiley', '>:o' )" 
+                tooltiptext="&smiley10Cmd.tooltip;" />           
+      <menuitem class="smiley insert-cool menuitem-iconic"   label="&smiley11Cmd.label;"
+                oncommand="doStatefulCommand('cmd_smiley', '8-)' )" 
+                tooltiptext="&smiley11Cmd.tooltip;" />           
+      <menuitem class="smiley insert-money menuitem-iconic"   label="&smiley12Cmd.label;"
+                oncommand="doStatefulCommand('cmd_smiley', ':-$' )" 
+                tooltiptext="&smiley12Cmd.tooltip;" />           
+      <menuitem class="smiley insert-foot menuitem-iconic"   label="&smiley13Cmd.label;"
+                oncommand="doStatefulCommand('cmd_smiley', ':-!' )" 
+                tooltiptext="&smiley13Cmd.tooltip;" />           
+      <menuitem class="smiley insert-innocent menuitem-iconic"   label="&smiley14Cmd.label;"
+                oncommand="doStatefulCommand('cmd_smiley', 'O:-)' )"
+                tooltiptext="&smiley14Cmd.tooltip;" />           
+      <menuitem class="smiley insert-cry menuitem-iconic"   label="&smiley15Cmd.label;"
+                oncommand="doStatefulCommand('cmd_smiley', ':\'(' )"
+                tooltiptext="&smiley15Cmd.tooltip;" />
+      <menuitem class="smiley insert-sealed menuitem-iconic"   label="&smiley16Cmd.label;"
+                oncommand="doStatefulCommand('cmd_smiley', ':-X' )"
+                tooltiptext="&smiley16Cmd.tooltip;" />           
+          
+    </menupopup>
+  </toolbarbutton>
+
+  <menu id="insertMenu">
+    <menupopup id="insertMenuPopup">
+      <menu id="insertSmiley" label="&insertSmiley.label;" accesskey="&insertSmiley.accesskey;" insertbefore="insertMenuSeparator">
+        <menupopup id="smilyPopup">
+          <menuitem class="smiley insert-smile menuitem-iconic"       label="&smiley1Cmd.label;" 
+                    oncommand="doStatefulCommand('cmd_smiley', ':-)'  )" accesskey="&smiley1Cmd.accesskey;"/>
+          <menuitem class="smiley insert-frown menuitem-iconic"       label="&smiley2Cmd.label;"
+                    oncommand="doStatefulCommand('cmd_smiley', ':-('  )" accesskey="&smiley2Cmd.accesskey;"/>                                              
+          <menuitem class="smiley insert-wink menuitem-iconic"        label="&smiley3Cmd.label;"
+                    oncommand="doStatefulCommand('cmd_smiley', ';-)'  )" accesskey="&smiley3Cmd.accesskey;"/>                       
+          <menuitem class="smiley insert-tongue menuitem-iconic"      label="&smiley4Cmd.label;"
+                    oncommand="doStatefulCommand('cmd_smiley', ':-P'  )" accesskey="&smiley4Cmd.accesskey;"/>
+          <menuitem class="smiley insert-laughing menuitem-iconic"    label="&smiley5Cmd.label;"
+                    oncommand="doStatefulCommand('cmd_smiley', ':-D'  )" accesskey="&smiley5Cmd.accesskey;"/>
+          <menuitem class="smiley insert-embarrassed menuitem-iconic" label="&smiley6Cmd.label;"
+                    oncommand="doStatefulCommand('cmd_smiley', ':-['  )" accesskey="&smiley6Cmd.accesskey;"/>
+          <menuitem class="smiley insert-undecided menuitem-iconic"   label="&smiley7Cmd.label;"
+                    oncommand="doStatefulCommand('cmd_smiley', ':-\\' )" accesskey="&smiley7Cmd.accesskey;"/>
+          <menuitem class="smiley insert-surprise menuitem-iconic"   label="&smiley8Cmd.label;"
+                    oncommand="doStatefulCommand('cmd_smiley', '=-O' )" accesskey="&smiley8Cmd.accesskey;"/>           
+          <menuitem class="smiley insert-kiss menuitem-iconic"   label="&smiley9Cmd.label;"
+                    oncommand="doStatefulCommand('cmd_smiley', ':-*' )" accesskey="&smiley9Cmd.accesskey;"/>           
+          <menuitem class="smiley insert-yell menuitem-iconic"   label="&smiley10Cmd.label;"
+                    oncommand="doStatefulCommand('cmd_smiley', '>:o' )" accesskey="&smiley10Cmd.accesskey;"/>           
+          <menuitem class="smiley insert-cool menuitem-iconic"   label="&smiley11Cmd.label;"
+                    oncommand="doStatefulCommand('cmd_smiley', '8-)' )" accesskey="&smiley11Cmd.accesskey;"/>           
+          <menuitem class="smiley insert-money menuitem-iconic"   label="&smiley12Cmd.label;"
+                    oncommand="doStatefulCommand('cmd_smiley', ':-$' )" accesskey="&smiley12Cmd.accesskey;"/>           
+          <menuitem class="smiley insert-foot menuitem-iconic"   label="&smiley13Cmd.label;"
+                    oncommand="doStatefulCommand('cmd_smiley', ':-!' )" accesskey="&smiley13Cmd.accesskey;"/>           
+          <menuitem class="smiley insert-innocent menuitem-iconic"   label="&smiley14Cmd.label;"
+                    oncommand="doStatefulCommand('cmd_smiley', 'O:-)' )" accesskey="&smiley14Cmd.accesskey;"/>           
+          <menuitem class="smiley insert-cry menuitem-iconic"   label="&smiley15Cmd.label;"
+                    oncommand="doStatefulCommand('cmd_smiley', ':\'(' )" accesskey="&smiley15Cmd.accesskey;"/>           
+          <menuitem class="smiley insert-sealed menuitem-iconic"   label="&smiley16Cmd.label;"
+                    oncommand="doStatefulCommand('cmd_smiley', ':-X' )" accesskey="&smiley16Cmd.accesskey;"/>            
+        </menupopup>
+      </menu>           
+    </menupopup>
+  </menu>
+</overlay>
new file mode 100644
--- /dev/null
+++ b/editor/ui/composer/content/editorTasksOverlay.xul
@@ -0,0 +1,76 @@
+<?xml version="1.0"?>
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Editor Tasks Overlay.
+   -
+   - The Initial Developer of the Original Code is
+   - Neil Rashbrook.
+   - Portions created by the Initial Developer are Copyright (C) 2001
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s): Neil Rashbrook <neil@parkwaycc.co.uk>
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either the GNU General Public License Version 2 or later (the "GPL"), or
+   - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the LGPL or the GPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!DOCTYPE overlay SYSTEM "chrome://communicator/locale/tasksOverlay.dtd">
+
+<overlay id="editorTasksOverlay"
+         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+  <script type="application/x-javascript">
+  <![CDATA[
+    function toEditor()
+    {
+      if (!CycleWindow("composer:html"))
+        NewEditorWindow();
+    }
+    function NewEditorWindow()
+    {
+      // Open editor window with blank page
+      window.openDialog( "chrome://editor/content", "_blank", "chrome,all,dialog=no", "about:blank");
+    }
+  ]]>
+  </script>         
+
+  <keyset id="tasksKeys">
+    <key id="key_editor" key="&editorCmd.commandkey;" command="Tasks:Editor" modifiers="accel"/>
+  </keyset>
+
+  <commandset id="tasksCommands">
+    <command id="Tasks:Editor" oncommand="toEditor();"/>
+  </commandset>
+
+  <statusbarpanel id="component-bar">
+    <toolbarbutton class="taskbutton" id="mini-comp" command="Tasks:Editor" 
+                   tooltiptext="&taskComposer.tooltip;" insertafter="mini-nav"/>
+  </statusbarpanel>
+  
+  <menupopup id="windowPopup">
+    <menuitem label="&editorCmd.label;" accesskey="&editorCmd.accesskey;" key="key_editor" command="Tasks:Editor" id="tasksMenuEditor" insertafter="IMMenuItem,tasksMenuNavigator" class="menuitem-iconic icon-composer16 menu-iconic"/>
+  </menupopup>
+  
+</overlay>         
+
new file mode 100644
--- /dev/null
+++ b/editor/ui/composer/content/editorUtilities.js
@@ -0,0 +1,1106 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Pete Collins
+ *   Brian King
+ *   Daniel Glazman <glazman@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**** NAMESPACES ****/
+const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+
+// Each editor window must include this file
+// Variables  shared by all dialogs:
+
+// Object to attach commonly-used widgets (all dialogs should use this)
+var gDialog = {};
+
+const kOutputEncodeBasicEntities = Components.interfaces.nsIDocumentEncoder.OutputEncodeBasicEntities;
+const kOutputEncodeHTMLEntities = Components.interfaces.nsIDocumentEncoder.OutputEncodeHTMLEntities;
+const kOutputEncodeLatin1Entities = Components.interfaces.nsIDocumentEncoder.OutputEncodeLatin1Entities;
+const kOutputEncodeW3CEntities = Components.interfaces.nsIDocumentEncoder.OutputEncodeW3CEntities;
+const kOutputFormatted = Components.interfaces.nsIDocumentEncoder.OutputFormatted;
+const kOutputLFLineBreak = Components.interfaces.nsIDocumentEncoder.OutputLFLineBreak;
+const kOutputSelectionOnly = Components.interfaces.nsIDocumentEncoder.OutputSelectionOnly;
+const kOutputWrap = Components.interfaces.nsIDocumentEncoder.OutputWrap;
+
+var gStringBundle;
+var gIOService;
+var gPrefsService;
+var gPrefsBranch;
+var gFilePickerDirectory;
+
+var gOS = "";
+const gWin = "Win";
+const gUNIX = "UNIX";
+const gMac = "Mac";
+
+const kWebComposerWindowID = "editorWindow";
+const kMailComposerWindowID = "msgcomposeWindow";
+
+var gIsHTMLEditor;
+/************* Message dialogs ***************/
+
+function AlertWithTitle(title, message, parentWindow)
+{
+  if (!parentWindow)
+    parentWindow = window;
+
+  var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService();
+  promptService = promptService.QueryInterface(Components.interfaces.nsIPromptService);
+
+  if (promptService)
+  {
+    if (!title)
+      title = GetString("Alert");
+
+    // "window" is the calling dialog window
+    promptService.alert(parentWindow, title, message);
+  }
+}
+
+// Optional: Caller may supply text to substitue for "Ok" and/or "Cancel"
+function ConfirmWithTitle(title, message, okButtonText, cancelButtonText)
+{
+  var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService();
+  promptService = promptService.QueryInterface(Components.interfaces.nsIPromptService);
+
+  if (promptService)
+  {
+    var okFlag = okButtonText ? promptService.BUTTON_TITLE_IS_STRING : promptService.BUTTON_TITLE_OK;
+    var cancelFlag = cancelButtonText ? promptService.BUTTON_TITLE_IS_STRING : promptService.BUTTON_TITLE_CANCEL;
+
+    return promptService.confirmEx(window, title, message,
+                            (okFlag * promptService.BUTTON_POS_0) +
+                            (cancelFlag * promptService.BUTTON_POS_1),
+                            okButtonText, cancelButtonText, null, null, {value:0}) == 0;
+  }
+  return false;
+}
+
+/************* String Utilities ***************/
+
+function GetString(name)
+{
+  if (!gStringBundle)
+  {
+    try {
+      var strBundleService =
+          Components.classes["@mozilla.org/intl/stringbundle;1"].getService(); 
+      strBundleService = 
+          strBundleService.QueryInterface(Components.interfaces.nsIStringBundleService);
+
+      gStringBundle = strBundleService.createBundle("chrome://editor/locale/editor.properties"); 
+
+    } catch (ex) {}
+  }
+  if (gStringBundle)
+  {
+    try {
+      return gStringBundle.GetStringFromName(name);
+    } catch (e) {}
+  }
+  return null;
+}
+
+function TrimStringLeft(string)
+{
+  if(!string) return "";
+  return string.replace(/^\s+/, "");
+}
+
+function TrimStringRight(string)
+{
+  if (!string) return "";
+  return string.replace(/\s+$/, '');
+}
+
+// Remove whitespace from both ends of a string
+function TrimString(string)
+{
+  if (!string) return "";
+  return string.replace(/(^\s+)|(\s+$)/g, '')
+}
+
+function IsWhitespace(string)
+{
+  return /^\s/.test(string);
+}
+
+function TruncateStringAtWordEnd(string, maxLength, addEllipses)
+{
+  // Return empty if string is null, undefined, or the empty string
+  if (!string)
+    return "";
+
+  // We assume they probably don't want whitespace at the beginning
+  string = string.replace(/^\s+/, '');
+  if (string.length <= maxLength)
+    return string;
+
+  // We need to truncate the string to maxLength or fewer chars
+  if (addEllipses)
+    maxLength -= 3;
+  string = string.replace(RegExp("(.{0," + maxLength + "})\\s.*"), "$1")
+
+  if (string.length > maxLength)
+    string = string.slice(0, maxLength);
+
+  if (addEllipses)
+    string += "...";
+  return string;
+}
+
+// Replace all whitespace characters with supplied character
+// E.g.: Use charReplace = " ", to "unwrap" the string by removing line-end chars
+//       Use charReplace = "_" when you don't want spaces (like in a URL)
+function ReplaceWhitespace(string, charReplace)
+{
+  return string.replace(/(^\s+)|(\s+$)/g,'').replace(/\s+/g,charReplace)
+}
+
+// Replace whitespace with "_" and allow only HTML CDATA
+//   characters: "a"-"z","A"-"Z","0"-"9", "_", ":", "-", ".",
+//   and characters above ASCII 127
+function ConvertToCDATAString(string)
+{
+  return string.replace(/\s+/g,"_").replace(/[^a-zA-Z0-9_\.\-\:\u0080-\uFFFF]+/g,'');
+}
+
+function GetSelectionAsText()
+{
+  try {
+    return GetCurrentEditor().outputToString("text/plain", kOutputSelectionOnly);
+  } catch (e) {}
+
+  return "";
+}
+
+
+/************* Get Current Editor and associated interfaces or info ***************/
+const nsIPlaintextEditor = Components.interfaces.nsIPlaintextEditor;
+const nsIHTMLEditor = Components.interfaces.nsIHTMLEditor;
+const nsITableEditor = Components.interfaces.nsITableEditor;
+const nsIEditorStyleSheets = Components.interfaces.nsIEditorStyleSheets;
+const nsIEditingSession = Components.interfaces.nsIEditingSession;
+
+function GetCurrentEditor()
+{
+  // Get the active editor from the <editor> tag
+  // XXX This will probably change if we support > 1 editor in main Composer window
+  //      (e.g. a plaintext editor for HTMLSource)
+
+  // For dialogs: Search up parent chain to find top window with editor
+  var editor;
+  try {
+    var editorElement = GetCurrentEditorElement();
+    editor = editorElement.getEditor(editorElement.contentWindow);
+
+    // Do QIs now so editor users won't have to figure out which interface to use
+    // Using "instanceof" does the QI for us.
+    editor instanceof Components.interfaces.nsIPlaintextEditor;
+    editor instanceof Components.interfaces.nsIHTMLEditor;
+  } catch (e) { dump (e)+"\n"; }
+
+  return editor;
+}
+
+function GetCurrentTableEditor()
+{
+  var editor = GetCurrentEditor();
+  return (editor && (editor instanceof nsITableEditor)) ? editor : null;
+}
+
+function GetCurrentEditorElement()
+{
+  var tmpWindow = window;
+  
+  do {
+    // Get the <editor> element(s)
+    var editorList = tmpWindow.document.getElementsByTagName("editor");
+
+    // This will change if we support > 1 editor element
+    if (editorList.item(0))
+      return editorList.item(0);
+
+    tmpWindow = tmpWindow.opener;
+  } 
+  while (tmpWindow);
+
+  return null;
+}
+
+function GetCurrentCommandManager()
+{
+  try {
+    return GetCurrentEditorElement().commandManager;
+  } catch (e) { dump (e)+"\n"; }
+
+  return null;
+}
+
+function GetCurrentEditorType()
+{
+  try {
+    return GetCurrentEditorElement().editortype;
+  } catch (e) { dump (e)+"\n"; }
+
+  return "";
+}
+
+function IsHTMLEditor()
+{
+  // We don't have an editorElement, just return false
+  if (!GetCurrentEditorElement())
+    return false;
+
+  var editortype = GetCurrentEditorType();
+  switch (editortype)
+  {
+      case "html":
+      case "htmlmail":
+        return true;
+
+      case "text":
+      case "textmail":
+        return false
+
+      default:
+        dump("INVALID EDITOR TYPE: " + editortype + "\n");
+        break;
+  }
+  return false;
+}
+
+function PageIsEmptyAndUntouched()
+{
+  return IsDocumentEmpty() && !IsDocumentModified() && !IsHTMLSourceChanged();
+}
+
+function IsInHTMLSourceMode()
+{
+  return (gEditorDisplayMode == kDisplayModeSource);
+}
+
+// are we editing HTML (i.e. neither in HTML source mode, nor editing a text file)
+function IsEditingRenderedHTML()
+{
+  return IsHTMLEditor() && !IsInHTMLSourceMode();
+}
+
+function IsWebComposer()
+{
+  return document.documentElement.id == "editorWindow";
+}
+
+function IsDocumentEditable()
+{
+  try {
+    return GetCurrentEditor().isDocumentEditable;
+  } catch (e) {}
+  return false;
+}
+
+function IsDocumentEmpty()
+{
+  try {
+    return GetCurrentEditor().documentIsEmpty;
+  } catch (e) {}
+  return false;
+}
+
+function IsDocumentModified()
+{
+  try {
+    return GetCurrentEditor().documentModified;
+  } catch (e) {}
+  return false;
+}
+
+function IsHTMLSourceChanged()
+{
+  return gSourceTextEditor.documentModified;
+}
+
+function newCommandParams()
+{
+  try {
+    return Components.classes["@mozilla.org/embedcomp/command-params;1"].createInstance(Components.interfaces.nsICommandParams);
+  }
+  catch(e) { dump("error thrown in newCommandParams: "+e+"\n"); }
+  return null;
+}
+
+/************* General editing command utilities ***************/
+
+function GetDocumentTitle()
+{
+  try {
+    return new XPCNativeWrapper(GetCurrentEditor().document, "title").title;
+  } catch (e) {}
+
+  return "";
+}
+
+function SetDocumentTitle(title)
+{
+
+  try {
+    GetCurrentEditor().setDocumentTitle(title);
+
+    // Update window title (doesn't work if called from a dialog)
+    if ("UpdateWindowTitle" in window)
+      window.UpdateWindowTitle();
+  } catch (e) {}
+}
+
+var gAtomService;
+function GetAtomService()
+{
+  gAtomService = Components.classes["@mozilla.org/atom-service;1"].getService(Components.interfaces.nsIAtomService);
+}
+
+function EditorGetTextProperty(property, attribute, value, firstHas, anyHas, allHas)
+{
+  try {
+    if (!gAtomService) GetAtomService();
+    var propAtom = gAtomService.getAtom(property);
+
+    GetCurrentEditor().getInlineProperty(propAtom, attribute, value,
+                                         firstHas, anyHas, allHas);
+  }
+  catch(e) {}
+}
+
+function EditorSetTextProperty(property, attribute, value)
+{
+  try {
+    if (!gAtomService) GetAtomService();
+    var propAtom = gAtomService.getAtom(property);
+
+    GetCurrentEditor().setInlineProperty(propAtom, attribute, value);
+    if ("gContentWindow" in window)
+      window.gContentWindow.focus();
+  }
+  catch(e) {}
+}
+
+function EditorRemoveTextProperty(property, attribute)
+{
+  try {
+    if (!gAtomService) GetAtomService();
+    var propAtom = gAtomService.getAtom(property);
+
+    GetCurrentEditor().removeInlineProperty(propAtom, attribute);
+    if ("gContentWindow" in window)
+      window.gContentWindow.focus();
+  }
+  catch(e) {}
+}
+
+/************* Element enbabling/disabling ***************/
+
+// this function takes an elementID and a flag
+// if the element can be found by ID, then it is either enabled (by removing "disabled" attr)
+// or disabled (setAttribute) as specified in the "doEnable" parameter
+function SetElementEnabledById(elementID, doEnable)
+{
+  SetElementEnabled(document.getElementById(elementID), doEnable);
+}
+
+function SetElementEnabled(element, doEnable)
+{
+  if ( element )
+  {
+    if ( doEnable )
+      element.removeAttribute("disabled");
+    else
+      element.setAttribute("disabled", "true");
+  }
+  else
+  {
+    dump("Element  not found in SetElementEnabled\n");
+  }
+}
+
+/************* Services / Prefs ***************/
+
+function GetIOService()
+{
+  if (gIOService)
+    return gIOService;
+
+  gIOService = Components.classes["@mozilla.org/network/io-service;1"]
+               .getService(Components.interfaces.nsIIOService);
+
+  return gIOService;
+}
+
+function GetFileProtocolHandler()
+{
+  var ios = GetIOService();
+  var handler = ios.getProtocolHandler("file");
+  return handler.QueryInterface(Components.interfaces.nsIFileProtocolHandler);
+}
+
+function GetPrefsService()
+{
+  if (gPrefsService)
+    return gPrefsService;
+
+  try {
+    gPrefsService = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService);
+  }
+  catch(ex) {
+    dump("failed to get prefs service!\n");
+  }
+
+  return gPrefsService;
+}
+
+function GetPrefs()
+{
+  if (gPrefsBranch)
+    return gPrefsBranch;
+
+  try {
+    var prefService = GetPrefsService();
+    if (prefService)
+      gPrefsBranch = prefService.getBranch(null);
+
+    if (gPrefsBranch)
+      return gPrefsBranch;
+    else
+      dump("failed to get root prefs!\n");
+  }
+  catch(ex) {
+    dump("failed to get root prefs!\n");
+  }
+  return null;
+}
+
+function GetStringPref(name)
+{
+  try {
+    return GetPrefs().getComplexValue(name, Components.interfaces.nsISupportsString).data;
+  } catch (e) {}
+  return "";
+}
+
+function GetBoolPref(name)
+{
+  try {
+    return GetPrefs().getBoolPref(name);
+  } catch (e) {}
+  return false;
+}
+
+function SetUnicharPref(aPrefName, aPrefValue)
+{
+  var prefs = GetPrefs();
+  if (prefs)
+  {
+    try {
+      var str = Components.classes["@mozilla.org/supports-string;1"]
+                          .createInstance(Components.interfaces.nsISupportsString);
+      str.data = aPrefValue;
+      prefs.setComplexValue(aPrefName, Components.interfaces.nsISupportsString, str);
+    }
+    catch(e) {}
+  }
+}
+
+function GetUnicharPref(aPrefName, aDefVal)
+{
+  var prefs = GetPrefs();
+  if (prefs)
+  {
+    try {
+      return prefs.getComplexValue(aPrefName, Components.interfaces.nsISupportsString).data;
+    }
+    catch(e) {}
+  }
+  return "";
+}
+
+// Set initial directory for a filepicker from URLs saved in prefs
+function SetFilePickerDirectory(filePicker, fileType)
+{
+  if (filePicker)
+  {
+    try {
+      var prefBranch = GetPrefs();
+      if (prefBranch)
+      {
+        // Save current directory so we can reset it in SaveFilePickerDirectory
+        gFilePickerDirectory = filePicker.displayDirectory;
+
+        var location = prefBranch.getComplexValue("editor.lastFileLocation."+fileType, Components.interfaces.nsILocalFile);
+        if (location)
+          filePicker.displayDirectory = location;
+      }
+    }
+    catch(e) {}
+  }
+}
+
+// Save the directory of the selected file to prefs
+function SaveFilePickerDirectory(filePicker, fileType)
+{
+  if (filePicker && filePicker.file)
+  {
+    try {
+      var prefBranch = GetPrefs();
+
+      var fileDir;
+      if (filePicker.file.parent)
+        fileDir = filePicker.file.parent.QueryInterface(Components.interfaces.nsILocalFile);
+
+      if (prefBranch)
+       prefBranch.setComplexValue("editor.lastFileLocation."+fileType, Components.interfaces.nsILocalFile, fileDir);
+    
+      var prefsService = GetPrefsService();
+        prefsService.savePrefFile(null);
+    } catch (e) {}
+  }
+
+  // Restore the directory used before SetFilePickerDirectory was called;
+  // This reduces interference with Browser and other module directory defaults
+  if (gFilePickerDirectory)
+    filePicker.displayDirectory = gFilePickerDirectory;
+
+  gFilePickerDirectory = null;
+}
+
+function GetDefaultBrowserColors()
+{
+  var prefs = GetPrefs();
+  var colors = { TextColor:0, BackgroundColor:0, LinkColor:0, ActiveLinkColor:0 , VisitedLinkColor:0 };
+  var useSysColors = false;
+  try { useSysColors = prefs.getBoolPref("browser.display.use_system_colors"); } catch (e) {}
+
+  if (!useSysColors)
+  {
+    try { colors.TextColor = prefs.getCharPref("browser.display.foreground_color"); } catch (e) {}
+
+    try { colors.BackgroundColor = prefs.getCharPref("browser.display.background_color"); } catch (e) {}
+  }
+  // Use OS colors for text and background if explicitly asked or pref is not set
+  if (!colors.TextColor)
+    colors.TextColor = "windowtext";
+
+  if (!colors.BackgroundColor)
+    colors.BackgroundColor = "window";
+
+  colors.LinkColor = prefs.getCharPref("browser.anchor_color");
+  colors.ActiveLinkColor = prefs.getCharPref("browser.active_color");
+  colors.VisitedLinkColor = prefs.getCharPref("browser.visited_color");
+
+  return colors;
+}
+
+/************* URL handling ***************/
+
+function TextIsURI(selectedText)
+{
+  return selectedText && /^http:\/\/|^https:\/\/|^file:\/\/|\
+    ^ftp:\/\/|^about:|^mailto:|^news:|^snews:|^telnet:|^ldap:|\
+    ^ldaps:|^gopher:|^finger:|^javascript:/i.test(selectedText);
+}
+
+function IsUrlAboutBlank(urlString)
+{
+  return (urlString == "about:blank");
+}
+
+function MakeRelativeUrl(url)
+{
+  var inputUrl = TrimString(url);
+  if (!inputUrl)
+    return inputUrl;
+
+  // Get the filespec relative to current document's location
+  // NOTE: Can't do this if file isn't saved yet!
+  var docUrl = GetDocumentBaseUrl();
+  var docScheme = GetScheme(docUrl);
+
+  // Can't relativize if no doc scheme (page hasn't been saved)
+  if (!docScheme)
+    return inputUrl;
+
+  var urlScheme = GetScheme(inputUrl);
+
+  // Do nothing if not the same scheme or url is already relativized
+  if (docScheme != urlScheme)
+    return inputUrl;
+
+  var IOService = GetIOService();
+  if (!IOService)
+    return inputUrl;
+
+  // Host must be the same
+  var docHost = GetHost(docUrl);
+  var urlHost = GetHost(inputUrl);
+  if (docHost != urlHost)
+    return inputUrl;
+
+
+  // Get just the file path part of the urls
+  // XXX Should we use GetCurrentEditor().documentCharacterSet for 2nd param ?
+  var docPath = IOService.newURI(docUrl, GetCurrentEditor().documentCharacterSet, null).path;
+  var urlPath = IOService.newURI(inputUrl, GetCurrentEditor().documentCharacterSet, null).path;
+
+  // We only return "urlPath", so we can convert
+  //  the entire docPath for case-insensitive comparisons
+  var os = GetOS();
+  var doCaseInsensitive = (docScheme == "file" && os == gWin);
+  if (doCaseInsensitive)
+    docPath = docPath.toLowerCase();
+
+  // Get document filename before we start chopping up the docPath
+  var docFilename = GetFilename(docPath);
+
+  // Both url and doc paths now begin with "/"
+  // Look for shared dirs starting after that
+  urlPath = urlPath.slice(1);
+  docPath = docPath.slice(1);
+
+  var firstDirTest = true;
+  var nextDocSlash = 0;
+  var done = false;
+
+  // Remove all matching subdirs common to both doc and input urls
+  do {
+    nextDocSlash = docPath.indexOf("\/");
+    var nextUrlSlash = urlPath.indexOf("\/");
+
+    if (nextUrlSlash == -1)
+    {
+      // We're done matching and all dirs in url
+      // what's left is the filename
+      done = true;
+
+      // Remove filename for named anchors in the same file
+      if (nextDocSlash == -1 && docFilename)
+      { 
+        var anchorIndex = urlPath.indexOf("#");
+        if (anchorIndex > 0)
+        {
+          var urlFilename = doCaseInsensitive ? urlPath.toLowerCase() : urlPath;
+        
+          if (urlFilename.indexOf(docFilename) == 0)
+            urlPath = urlPath.slice(anchorIndex);
+        }
+      }
+    }
+    else if (nextDocSlash >= 0)
+    {
+      // Test for matching subdir
+      var docDir = docPath.slice(0, nextDocSlash);
+      var urlDir = urlPath.slice(0, nextUrlSlash);
+      if (doCaseInsensitive)
+        urlDir = urlDir.toLowerCase();
+
+      if (urlDir == docDir)
+      {
+
+        // Remove matching dir+"/" from each path
+        //  and continue to next dir
+        docPath = docPath.slice(nextDocSlash+1);
+        urlPath = urlPath.slice(nextUrlSlash+1);
+      }
+      else
+      {
+        // No match, we're done
+        done = true;
+
+        // Be sure we are on the same local drive or volume 
+        //   (the first "dir" in the path) because we can't 
+        //   relativize to different drives/volumes.
+        // UNIX doesn't have volumes, so we must not do this else
+        //  the first directory will be misinterpreted as a volume name
+        if (firstDirTest && docScheme == "file" && os != gUNIX)
+          return inputUrl;
+      }
+    }
+    else  // No more doc dirs left, we're done
+      done = true;
+
+    firstDirTest = false;
+  }
+  while (!done);
+
+  // Add "../" for each dir left in docPath
+  while (nextDocSlash > 0)
+  {
+    urlPath = "../" + urlPath;
+    nextDocSlash = docPath.indexOf("\/", nextDocSlash+1);
+  }
+  return urlPath;
+}
+
+function MakeAbsoluteUrl(url)
+{
+  var resultUrl = TrimString(url);
+  if (!resultUrl)
+    return resultUrl;
+
+  // Check if URL is already absolute, i.e., it has a scheme
+  var urlScheme = GetScheme(resultUrl);
+
+  if (urlScheme)
+    return resultUrl;
+
+  var docUrl = GetDocumentBaseUrl();
+  var docScheme = GetScheme(docUrl);
+
+  // Can't relativize if no doc scheme (page hasn't been saved)
+  if (!docScheme)
+    return resultUrl;
+
+  var  IOService = GetIOService();
+  if (!IOService)
+    return resultUrl;
+  
+  // Make a URI object to use its "resolve" method
+  var absoluteUrl = resultUrl;
+  var docUri = IOService.newURI(docUrl, GetCurrentEditor().documentCharacterSet, null);
+
+  try {
+    absoluteUrl = docUri.resolve(resultUrl);
+    // This is deprecated and buggy! 
+    // If used, we must make it a path for the parent directory (remove filename)
+    //absoluteUrl = IOService.resolveRelativePath(resultUrl, docUrl);
+  } catch (e) {}
+
+  return absoluteUrl;
+}
+
+// Get the HREF of the page's <base> tag or the document location
+// returns empty string if no base href and document hasn't been saved yet
+function GetDocumentBaseUrl()
+{
+  try {
+    var docUrl;
+
+    // if document supplies a <base> tag, use that URL instead 
+    var baseList = GetCurrentEditor().document.getElementsByTagName("base");
+    if (baseList)
+    {
+      var base = baseList.item(0);
+      if (base)
+        docUrl = base.getAttribute("href");
+    }
+    if (!docUrl)
+      docUrl = GetDocumentUrl();
+
+    if (!IsUrlAboutBlank(docUrl))
+      return docUrl;
+  } catch (e) {}
+  return "";
+}
+
+function GetDocumentUrl()
+{
+  try {
+    var aDOMHTMLDoc = GetCurrentEditor().document.QueryInterface(Components.interfaces.nsIDOMHTMLDocument);
+    return aDOMHTMLDoc.URL;
+  }
+  catch (e) {}
+  return "";
+}
+
+// Extract the scheme (e.g., 'file', 'http') from a URL string
+function GetScheme(urlspec)
+{
+  var resultUrl = TrimString(urlspec);
+  // Unsaved document URL has no acceptable scheme yet
+  if (!resultUrl || IsUrlAboutBlank(resultUrl))
+    return "";
+
+  var IOService = GetIOService();
+  if (!IOService)
+    return "";
+
+  var scheme = "";
+  try {
+    // This fails if there's no scheme
+    scheme = IOService.extractScheme(resultUrl);
+  } catch (e) {}
+
+  return scheme ? scheme.toLowerCase() : "";
+}
+
+function GetHost(urlspec)
+{
+  if (!urlspec)
+    return "";
+
+  var IOService = GetIOService();
+  if (!IOService)
+    return "";
+
+  var host = "";
+  try {
+    host = IOService.newURI(urlspec, null, null).host;
+   } catch (e) {}
+
+  return host;
+}
+
+function GetUsername(urlspec)
+{
+  if (!urlspec)
+    return "";
+
+  var IOService = GetIOService();
+  if (!IOService)
+    return "";
+
+  var username = "";
+  try {
+    username = IOService.newURI(urlspec, null, null).username;
+  } catch (e) {}
+
+  return username;
+}
+
+function GetFilename(urlspec)
+{
+  if (!urlspec || IsUrlAboutBlank(urlspec))
+    return "";
+
+  var IOService = GetIOService();
+  if (!IOService)
+    return "";
+
+  var filename;
+
+  try {
+    var uri = IOService.newURI(urlspec, null, null);
+    if (uri)
+    {
+      var url = uri.QueryInterface(Components.interfaces.nsIURL);
+      if (url)
+        filename = url.fileName;
+    }
+  } catch (e) {}
+
+  return filename ? filename : "";
+}
+
+// Return the url without username and password
+// Optional output objects return extracted username and password strings
+// This uses just string routines via nsIIOServices
+function StripUsernamePassword(urlspec, usernameObj, passwordObj)
+{
+  urlspec = TrimString(urlspec);
+  if (!urlspec || IsUrlAboutBlank(urlspec))
+    return urlspec;
+
+  if (usernameObj)
+    usernameObj.value = "";
+  if (passwordObj)
+    passwordObj.value = "";
+
+  // "@" must exist else we will never detect username or password
+  var atIndex = urlspec.indexOf("@");
+  if (atIndex > 0)
+  {
+    try {
+      var IOService = GetIOService();
+      if (!IOService)
+        return urlspec;
+
+      var uri = IOService.newURI(urlspec, null, null);
+      var username = uri.username;
+      var password = uri.password;
+
+      if (usernameObj && username)
+        usernameObj.value = username;
+      if (passwordObj && password)
+        passwordObj.value = password;
+      if (username)
+      {
+        var usernameStart = urlspec.indexOf(username);
+        if (usernameStart != -1)
+          return urlspec.slice(0, usernameStart) + urlspec.slice(atIndex+1);
+      }
+    } catch (e) {}
+  }
+  return urlspec;
+}
+
+function StripPassword(urlspec, passwordObj)
+{
+  urlspec = TrimString(urlspec);
+  if (!urlspec || IsUrlAboutBlank(urlspec))
+    return urlspec;
+
+  if (passwordObj)
+    passwordObj.value = "";
+
+  // "@" must exist else we will never detect password
+  var atIndex = urlspec.indexOf("@");
+  if (atIndex > 0)
+  {
+    try {
+      var IOService = GetIOService();
+      if (!IOService)
+        return urlspec;
+
+      var password = IOService.newURI(urlspec, null, null).password;
+
+      if (passwordObj && password)
+        passwordObj.value = password;
+      if (password)
+      {
+        // Find last ":" before "@"
+        var colon = urlspec.lastIndexOf(":", atIndex);
+        if (colon != -1)
+        {
+          // Include the "@"
+          return urlspec.slice(0, colon) + urlspec.slice(atIndex);
+        }
+      }
+    } catch (e) {}
+  }
+  return urlspec;
+}
+
+// Version to use when you have an nsIURI object
+function StripUsernamePasswordFromURI(uri)
+{
+  var urlspec = "";
+  if (uri)
+  {
+    try {
+      urlspec = uri.spec;
+      var userPass = uri.userPass;
+      if (userPass)
+      {
+        start = urlspec.indexOf(userPass);
+        urlspec = urlspec.slice(0, start) + urlspec.slice(start+userPass.length+1);
+      }
+    } catch (e) {}    
+  }
+  return urlspec;
+}
+
+function InsertUsernameIntoUrl(urlspec, username)
+{
+  if (!urlspec || !username)
+    return urlspec;
+
+  try {
+    var ioService = GetIOService();
+    var URI = ioService.newURI(urlspec, GetCurrentEditor().documentCharacterSet, null);
+    URI.username = username;
+    return URI.spec;
+  } catch (e) {}
+
+  return urlspec;
+}
+
+function GetOS()
+{
+  if (gOS)
+    return gOS;
+
+  var platform = navigator.platform.toLowerCase();
+
+  if (platform.indexOf("win") != -1)
+    gOS = gWin;
+  else if (platform.indexOf("mac") != -1)
+    gOS = gMac;
+  else if (platform.indexOf("unix") != -1 || platform.indexOf("linux") != -1 || platform.indexOf("sun") != -1)
+    gOS = gUNIX;
+  else
+    gOS = "";
+  // Add other tests?
+
+  return gOS;
+}
+
+function ConvertRGBColorIntoHEXColor(color)
+{
+  if ( /rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/.test(color) ) {
+    var r = Number(RegExp.$1).toString(16);
+    if (r.length == 1) r = "0"+r;
+    var g = Number(RegExp.$2).toString(16);
+    if (g.length == 1) g = "0"+g;
+    var b = Number(RegExp.$3).toString(16);
+    if (b.length == 1) b = "0"+b;
+    return "#"+r+g+b;
+  }
+  else
+  {
+    return color;
+  }
+}
+
+/************* CSS ***************/
+
+function GetHTMLOrCSSStyleValue(element, attrName, cssPropertyName)
+{
+  var prefs = GetPrefs();
+  var IsCSSPrefChecked = prefs.getBoolPref("editor.use_css");
+  var value;
+  if (IsCSSPrefChecked && IsHTMLEditor())
+    value = element.style.getPropertyValue(cssPropertyName);
+
+  if (!value)
+    value = element.getAttribute(attrName);
+
+  if (!value)
+    return "";
+
+  return value;
+}
+
+/************* Miscellaneous ***************/
+// Clone simple JS objects
+function Clone(obj) 
+{ 
+  var clone = {};
+  for (var i in obj)
+  {
+    if( typeof obj[i] == 'object')
+      clone[i] = Clone(obj[i]);
+    else
+      clone[i] = obj[i];
+  }
+  return clone;
+}
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3162d275d5a7eda06c34d2edc7ca9757ff059f32
GIT binary patch
literal 893
zc${<hbhEHb6l4%&_|CvEW$D&y*RK6%VE8`@M#0Dfia%Kx85o!tbQpjDlqVQCq8L~?
zSR4cz4m5M{Gf5mMXgJuyA#RrPLtqg@C#$hokB4Ey@qRh&xHlZ17N3~N;5DnoBOukI
sTQgQD<)zVqLz4|dlX@bGmpk=JYDURe1irX1k=Oswor*6R4h#&|02^i@3;+NC
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..78f142f47f1f33927242a4c884ecf1757f436301
GIT binary patch
literal 145
zc${<hbhEHb6l4%&*vtR|EiEno85sWmfBv5cp!k!8k%57UK?kH0WCjC^U4Vx}<DMT)
z2b#~`xK=2y(GeQe`sBgByvl7Kw9h-_Hcye8Z7JXSTskMuQC2G?CM!g9Ql`-)zx27%
L1*Lo47#OSp?8iyz
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..858bdfd499e479d7ee5963e01ba8c9e12fbea620
GIT binary patch
literal 897
zc${<hbhEHb6l4%&_|CvEW$D&y*RK6%VE8`@M#0Dfia%Kx85o!tbQpjDlqVQC;uu&t
zSR4cz4m5M{GjSX+XgJuyA#RrPLtqg@r!cozkHy4C4gJhoac^D-q<HknGR_dO+_do2
yQ~}dje@+xVI5R<7cpppW#f9gls<^)6ku+I!Y@UcNpU$c+sh5^97qhW2SOWmJWFo)-
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a25a2e2e8e9590f8a8c1e9e41f97de252bf79415
GIT binary patch
literal 148
zc${<hbhEHb6l4%&*vtR|EiEno85sWmfBv5cp!k!8k%57UK?kH0WCjC^V}OT4<DMT)
z2b#~`xK=2y(UBb5s%*K(xpJGF%x2w$)5Xi*D@=WRbT&`&>NEUppESx%ZW@X4uAHTE
QdC97`sk<kqurOEy0LRx&TL1t6
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3a63d01d1898c0f5fa9397dd705c6bab9dbfe272
GIT binary patch
literal 138
zc${<hbhEHb6lM@$Sj5io|9=A`BV$5B!h!`08X6o997u3*P&jblfZ|UUMg|6U1|0?<
z0I6kQ_Ltaor%JuSb2YEht=Nwfqyuy0A_UtUx$dV49K5mdS%}9A*Jy(%=B3<;5(;Oc
qL?SkcEfGl(R$h8CQgQXJ{^Z>WvMdiaRPe|-u)Ww))$7N=U=09T-7nz)
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..e97c5b8008e9664f8ccadc0f95cd48a75ba1a3fd
GIT binary patch
literal 202
zc$@*s05$(dNk%w1VIlw!0HOx~|Nnpi0Re!3Kww~CprD|@z+gZ?Ai%)DA^8LW000L7
zEC2ui03rYo000Az7`oj4?3@6qy*TR{#@t|Nbp&MzMO6r_ptdfswkbfGfM6Jv5U>V{
z4=DWU0;!wD;7j>>MQ9H9vkgirA#bSL8h2A-@@g6e!^hPZX{M4nEhCjRe*(Z(tUbI|
zi|qwfN(D7NGb|~GC^9iJV^|`Q8A_6s9AprgnhaM51D~LwqNAjt1QG<Ps;jK6uB!<E
EJAcni*8l(j
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0aefc06ff9a874bac8489cc05d199f1cba455528
GIT binary patch
literal 279
zc$@(j0qFimNk%w1VK@K~0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui05|{;06+uW7`oj4FvfEN2qNPW3IKwI0i0(TA8=j*skET=VWD;rgDk9{L3bB}
z2E`HjJPHphWD<=+BAhHmty-_xEH)t3dcR;RH|GMOLSkVEHTs}2s}U!FVu{|;g3|pd
zWRwDXFd!Kzfrd(ch#({_V-y6Dl9QB`mY0~9WMQ10Vgwb7DSn598H1*yf_j34fR0@%
zOfG<TZWcT$Y;-d%CnXmOD#BwHH9j#^NJ4FG$r~MQXuS(~In&8L8b~n6MLR%k+P5h`
dHpQOlp2ZUF?(Yvc6a)12_V@Vt`uqC{06PYCZ0Z02
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..e3f49a9635ab7a558fda28b1f76a4685750a0606
GIT binary patch
literal 240
zc$@+701y91Nk%w1VGsZ;0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui01yBy06+t^7`n`N0Z3qgnwE?xi}*q@1sVqk7%Gt)=8on2vSwk}H{5oZxW<x?
z;p5BfPCk#0BN(1kzoRT_`b0j<2`UGrX-~myuxZFqF$P6N4Df)8-Z7{P?4$#9X<MN1
zu?_@*f`fy4G9(Z^PZ)7vSa~K$N^BuSkP`&~Hvw>UC@Pm@Ls(~8A|aGWE{$$Plu4ma
qb8Hl9jGifMt*E6gd@6A^cutgeP)3m{ekBdf3K|as($mz`2>?4q5n9mz
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ccb809b50beeac3adadbe3670c3fba9eceb9d3a3
GIT binary patch
literal 127
zc${<hbhEHb6lM@$Sj5V3;6MT+BV$5B!h!`0{{L?{aNs~gg98HtgW^vXMg|5}1|1-q
z0i>3J*+pX4oha1_o~wD4q86EnH-~gS;+Ph)J@H}JvgNNg>WA0Ab(xfw_g^bk=jslg
fPRAMNlX)!XaR)d$tc_ZKg)!y8+p7I{SQxAUi(xMT
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f4faf7d23a7c38c0500bd5ffa7461a056a720dde
GIT binary patch
literal 230
zc$@*|02%*BNk%w1VJ-j=0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui04@L!06+t)7`oj45S|kN2qNPvtQD09de%mAWIzldAQ*-h7;jL38r_z3=FgeZ
zYIiCck4V`t$!sE3EK8yC;?-^#knRKwmO9F4p+M>g$etVN<|F$u=yPgyAlUEtynfH;
zN1cFxDimdCE^Pp8L26}hif}@I06J(USs^$?CMjT%m>32jU2a)snmwJH7fT}_6{@YS
gh+T3hVMKwsMNkpFzP}1|2Lr^##>dFX%E}1<J7)!2T>t<8
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f16f585235922d7bddad19e5703c64cd2c95a0b9
GIT binary patch
literal 212
zc$@*$04x7TNk%w1VI}|&0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui044ws06+to7`oj4@SFfD2qI%afiV?k0fLbkT}TXRRf6P(7MGdPHEsoKJO03+
zkjD}lk3nLqKq<ve0b0N&sF*IgOV3is3JTRqmz24M#X91Fz;3(W@VLB)tRHz3;8$GU
zlgl_@KuSL*Q87DJA|p&rBZL+lB~2J8J5(WtXIgZKE*Kq+HGqp3XOMQOKS~g-t`I8{
O1GBWXwzs&s2>?44l2AMV
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d54916a758cc355a164694068d9d53f506514562
GIT binary patch
literal 138
zc$@)>0CoRINk%w1VG{rl0IC20|Nnpi0Rf<(pkQENfPg^2z`#I2Ai%(2A^8LW000F5
zEC2ui022TZ06+sz7`ohAC4dQtoPkgfhPabO5C({O=BA$C>awOt8fw>4$2cCfR}8?Q
sa0tA;dXY^|x3a}9mY%VaAq998=SEh-!j4UpW4!Pc1n9JSjZOdnJ2ieap8x;=
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..de5a77335c1e9d0a789789618537b8acd2b81792
GIT binary patch
literal 216
zc$@*)04M)PNk%w1VGsZ$0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui01yBq06+ts7`n`N0RYj0kb#USizpL_X`Ix3X11AZt8&6sfbqCa1`Ze(@Ja&S
zq-TR&YBe9J#Z=yq$KJ2y5jkPG07!Uc6$}dE)Z|f!romv2JN3lgXU%~?uiNdnW{LpO
zv(QmPML>Z`ZEtXc5?}=jdrucahD#U<J0)W*6jGF57F>!rVSkiNC|#9cW{OaPs1yyH
Sd44YywsHppy1Tr*2>?6tEL8OX
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..4a8a8d2ef97e543a6051d444f020b6430e767924
GIT binary patch
literal 186
zc$@*c07d^tNk%w1VIBYw0IC20|Nnpi0Re!3K%k(YU|?WCKp?=tV8Fn@A^8LW000L7
zEC2ui03HAk06+tO7`oj4=L7)6q(Oj8O937Qej71dmLL>YP^^Ig7%nWAr>O6Ik6*rE
zFJMAtRwPbkqFiE%6oX22n+k4}sg5`}5We8BcudX-&s%~dY86?r6;;}7$+k43d?yKA
os#r2gbxn0Yc7HJ&FMu;OjD~2DTo06$3?>l+nwy-Ro}UQ-J5B#W#Q*>R
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a137f167c66fa450513bdb34e6e77aca45f7fe56
GIT binary patch
literal 176
zc$@*S08jr%Nk%w1VIBYw0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui03HAk06+tE7`oj4=LA53m^28WODL6Aam0X8mmnCJ$f|)clICpRcu<~rZ|k*6
zY9-^qd_Z17r2<);OVzJ*AXu;1tacmpc|!!rC@MuknbWQXbIAxi(9bA28nQr|Hb=1m
etL<_wd3SR=Uxzdgii-?X2Lq6il9QB`2>?5uvP6*p
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ae2b791e8d7150f03d0c25d7d55a395a43a4b1be
GIT binary patch
literal 281
zc$@(l0p|WkNk%w1VGsZ;0J{JH|Nnpi0Rf<(pkQENRaGj0fIzCMRX{)>z`$URjz_@2
zz~kd_IXN71aycCx4gdfEA^8LW000UAEC2ui01yBy06+xBFvv-%QUPd?_YQ;5X~Ci;
z1R0Ki;TonYdi1x}H8^i+YNVXoCV|tj2uMNzAsdYfheGoMJpiIpoX5DO0J)zeff(Fr
z7!AOJK?V<z%xn!M2NWhy`N0Z6IE7kr83j^=G71BUii?Y8fgl(jJuP2=0Fys;F*I%*
zF9va)EH;j75@~fKnPn^u3<e1fp_ZSUogQ?ol1WQ-G_z)V8h*e|8wiHF8+QQ*ampM4
fQk;MYQ3uV%A9jV)ZWYo^;Nu||0_W)I=@9@sXlP{|
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f91a05df15970b235f820b6bb4dae0a84a666aec
GIT binary patch
literal 214
zc$@*&04e`RNk%w1VGsZ$0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui01yBq06+tq7`n`N0RRz-yfTmxvCms46@p-08uxu^R|Lk1wUS_9h5)LQewDip
zaOk70W+BXLQA~~uiWtgiE0uD=3v_YI0$wMu7Z6>XjFd)ma3Hwfa5(P>f{c7D=ND={
z>!Dppb96>8IW`quKtF3j4FQcxB{F1AVqb}sJc~7v5?fJIgLg7$IR-aannF56UL;nN
QL65W>4+FTly1EGfI}JBY!2kdN
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..7f31b0ceed9bb0f5ea73a9080bc1fad5d02d2d60
GIT binary patch
literal 158
zc$@*A0Ac?}Nk%w1VHN-o0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui02Tlc06+s{7`ohjCjcPi45ChBCJ4k}Rhc1?f>~Ul<-PC=ig69kBbIik%F=*B
zCbJTH3ad}(KxjIjP$<x514SmnA$BN8DuEix$%XmlN&z9pBx_B2>2RU^bx~tDhu*O~
M4E}(Df`SPEJ0HtDHUIzs
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2c7dcac011f9e5f15ad2a75443cf863b01e8eaab
GIT binary patch
literal 264
zc$@(U0r&n#Nk%w1VK@K~0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui05|{;06+uH7`oj4FvfEN0K(oN02di(Tpp-h8Hs6zLUO7{3|c6(<UImKVCXB5
z@FOT>b{XRl^qQSw(5Q4uRRx^YtaiJ>27x@wE$l0Pi?&WOU_8OBUL~l&qvudeo^akF
z8U1}2c1;5Z1c!);ii?bmj*c{3l9O;17jl6pgBW?3XhL*>e|u(Kkt--CKWwNQt*I&*
ztSK9rGN(2zp&U4uH*9HbLZ}9-FSb{>AG)+FJwMDuCb1elZpdDg+FHpH-rwL5GZX{m
O=I7|?>g(+62>?5ymTPVR
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b8a0bbb744311ea11f45d2425601cfbdcf198d73
GIT binary patch
literal 247
zc$@+E00{p_Nk%w1VK@K~0IC20|Nnpi0Rh0kz<_{2prD{&U|_(&U_d}1A^8LW00062
zEC2ui05Sj&06+u07`oj4FfJhi7#4sqcE6dYY1nuiCdvVZ@&yH9VZ(4_D`?cgQP;Pc
zq2;?7Hi4sP6AO)=(5Q4uWy-49tQK~q*-*=pCPxa9OPte^YuWvjEa7tik3)YWdS1yD
z6#jsLf`f#GhJaUEii;yK6>)eZN;?-nbZ(KAA1rWsRx=r5Ibus?DW?ixIcy+6NnvK2
xAdQ=7bV;jCtv0V-WMs1%M7&2iL1Vg%%2{j@&d<<&0tD36*4NnC+S}C$06QIWWm^CM
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..dcb4229c612a4f096542454f103f1efa56bf5694
GIT binary patch
literal 192
zc$@*i06+gnNk%w1VI}|&0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui044ws06+tU7`oj4@SFf@EumCFxedY>S|kt<163Lzr?~=W#O54p<e8Ry@B2E{
zZ%C{JOCF>U^s$X{C?TnEyF3LrKx~^eq7H<xcuX#v&%2@;NSO4fSgUp$r^lgb3kK&&
unx0H-c^gtMOMp&1M=LEET8B+sC5vm7A5jpQnh;+H1D~LwqNAjx2>?4jC`gn5
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2a72bd010cbfdaf54c303482be0c89e7f109f148
GIT binary patch
literal 251
zc$@+I00jR>Nk%w1VKM*^0IC20|Nnpi0Re!3K%k(YU|?WCKp?=tV8Fn@A^8LW000L7
zEC2ui05Sj&06+u47`oj4Fs^d~Fu?#IY$+S?0f7*T;MS2QrmZJQ43=1S8deBJ#-2K!
zFR<%?Is)S+FssF$(5O_(q)o5bY}Eogl|rj;NbD^VIk&USx-ld*;AA{$QoU7h&ZX|1
z9SDGdf`f#GhKGS{S&NKI1Qj7}0(l&Acu#b2be58qYZfjl9w{h4AtM_jVk<B(TWCP0
zuw*|S3M4zLH+-))Nj^b68bov##7bg4ura-j&R1I!($myc6a(1V+S}aS-rv~?06RFL
BVx<58
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f72558c1e5580bcdf60e478c6fa8ca8998044981
GIT binary patch
literal 211
zc$@*#04)DUNk%w1VI}|&0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui044ws06+tn7`oj4@SFfZ38e~ZOa&dVRaX`W-xm-ART<}&U4{T>o3MF6Q0ti<
z%atk`kI2fZm25gwOV_A)`i!PMluw6J4pRkSiu(zZHC#b(c_6so@VI<VXFl)9)dVcI
z>dI+;Tx(wz7#bWrARbdCSw>NaV2_emRa<{vb|5i_G&YAhJ4!!lnnZZ1rx2{I5G)b{
Nva__cwzs$m06V)>P@4b%
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f8938feb4c44e6c4550e3d12cec86c770364fea4
GIT binary patch
literal 183
zc$@*Z07(BwNk%w1VIBYw0IC20|Nnpi0Rf<(pkQENfPg^2z+gZ?Ai%)DA^8LW000L7
zEC2ui03HAk06+tL7`oj4=L7&sD3nZNDBwUqcwR6F6J>}RW*Nkai6mvBb*}Gsy8pUf
z##b5*Lq?L&Qy>s99%oYOES(O6tai)odU3$8av&i!pCoA%ItE*ynomd7q1BdgCNes)
lw|y&47Zm|8G9fTkHYY@4Ks^tUk_%S{0+*PXnwy*n06YE6K~4Yw
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9ab2bc9de846b9e302828a24c90d5438ac91cda3
GIT binary patch
literal 262
zc$@(S0r~z%Nk%w1VKx8|0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui05$*+06+uF7`oj4FurpF040<wtT4joSy$PamSL1C5D1t8yTm{O#@lUIVDO!g
zFO&-vP8m>cqu{-IwOeUQty-^GY9N~JdcV`HjU#2jG=N}dmA;*xWY=c}7fX)<;IzP>
z?fpk4AtpR&PBjMvii?bmj*pO$k7Hn!mSF@He|di;c!Qsyej$K`oHUdfKqMI-ac!@#
zEf*~cY;|0)o;@H>YNKuzaIi0`xRf|LXv4}?Cviz4OfyAL$d}k&b`sp(-VKNc1LNf7
M=I7|?>gWjoJCZGJKL7v#
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b6ec228da1105b5b3a851dac6f05dff93d8947da
GIT binary patch
literal 229
zc$@*{02=>CNk%w1VGsZ;0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui01yBy06+t(7`n`N0mw;ZAS2p3Z>B;ZRGtP1Xj)j9$#rd46w1hc8+zL1OU9eR
zNC)U`CPbs}X41Hdz~XKS#VxB%pE4B+tguL~;H!-2lF@=;B!XFKC_@u-AlUDCymfhj
zAQdxhU`JjQWeq%0HY+ns9aCsl4T5D_QIm<1mR4e8judJJUxNU0Ybaz<e3y`!O#%jM
fYoAw2u@W??lB2Vv0767elf!fe1INh8$q4{EfACn0
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..dd15a3d5ae8098fd436da0aa82af620b2f5a155f
GIT binary patch
literal 159
zc$@*B0AT+|Nk%w1VHN-o0IC20|Nnpi0Re!3K%k(YU|?WCKp?=tV8Fn@A^8LW000L7
zEC2ui02Tlc06+s|7`ohjCjbz{ECmP&OfXYG3|vqM#ivzU7LME`&-6>yI4$0kwf-UB
zjw2`vKpmscb|5&P&}fvG%ZVZrCDNdr4TG1=X5vA9ds)dCOo4??DbS{9lAWu#p=0kD
NK?Z<<f`fwz06X7lJHr3~
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..1845e6b2ed71678e1770cb44cef99a7746c54f3b
GIT binary patch
literal 175
zc$@*R08sx&Nk%w1VIBYw0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui03HAk06+tD7`oj4=LA4O5Y!kTX6;oN5Q9erhF}B*cL^{Uo}@Y7_&k<*-|w~y
z1=NWZWV%`?CTIbUOeoB0Asq<Vtai)o@_b+sL9#Sbq*KfdC{k-&OIw9KR})`Nr1*PE
dty)D)cvN&@VL%UwiVIc;1CNlAl9QAP06VuhKOg`A
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..676c26ab1376d8f073ffc4ca3a0a760d93711330
GIT binary patch
literal 185
zc$@*b07m~uNk%w1VIBYw0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui03HAk06+tN7`oj4=LA55pvC}8>n+Mv5yMm&f)NxODqIS?i5qElc&_V#z5l>b
zslx#XCIJ`Al9>^Gl-ElpkVUQ4=ior-dcWYXco;0>dXkPbYg_{gSZj~$1T>44q(^%z
n9$Qm0ARshzeJCnRG<7P4P-bR^50jJ&BoPCdnwy-Ro(TXuhHFKe
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a5834b794723332b10e22e4ed262d813a659d606
GIT binary patch
literal 176
zc$@*S08jr%Nk%w1VIBYw0Ez$r|Nnpi0RdoOV4$F&fPg?iKp?=tV8Fn@A^8LW000L7
zEC2ui03HAk06+tE7`oj4=LA4$AhZ-f<^@JzRF*JIWKa-=$a!nGr6x+=cwU}*-v_nZ
z=S5TzWWpfncpQN+1ScmsI0&xTtai)g`MxyCjTxmFpky4-TN!GK7$S{riFb;t;oN3f
ewMKVtd;n{MU_Uhvii-;-5d)Bsl9QB`2>?6p8bdMw
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f190462e8c914e99e146b33cea98725b8de1e238
GIT binary patch
literal 168
zc$@*K09XG<Nk%w1VGsZq0IC20|Nnpi0Rf<(pkQENfPg^2z+gZ?Ai%)DA^8LW000L7
zEC2ui01yBe06+t67`n`N0RW;%kvI$yC&8YiaZ*7A#+7Xy=mKN=uH+2HuNizWE1e7;
z4p2Z52!?=a2wVs^hk<lTrPges0pz!v4KanJGJBmU47^^=WE+}}@TIRLPSH9@5Solf
W!}n@3Z7dCi3Qz|Eii?bl2>?5@7CY1c
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..6e94d42c16f22cb06e1e48f3a8248c9f9af298fd
GIT binary patch
literal 145
zc${<hbhEHb6krfxSjE8b|9=A`BjbVv3lb6%8X6oN925?KK!V~=7DfgJHU=FAAONX#
zU=EYmbtaARglDRR(zV*p(^wJ{qdaChEU%rcC7T%2q4|@|IFRM|3&s|=hHHjAeJ4^r
u9hY*9(73Li#mv<idLXg=^-nL>Q*XFWwH`A~3s%iZmTTHkW9QGnU=08WgfyrC
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d8fdc67c045a127ba0157e4a185a59e00aa2dbd8
GIT binary patch
literal 153
zc$@*50A~M3Nk%w1VHN-o0IC20|Nnpi0Rf<(pkQENfPg?iKp?=tV8Fn@A^8LW000L7
zEC2ui02Tlc06+s?7`ohjCx98qEM<bK_Ye|Q5Jg}Z1QCpu2X=6*1z#xNuFV1J+)_17
zDrM*pinGsQz-&67&lm1SiwK9vArUCuv@pI7t-I?{e!1DGg!GDoQ`y)-rz;PFynfH;
HCjbCD^&UIM
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f9b384271cf4eb7d6681a8eb0af941134de107a8
GIT binary patch
literal 155
zc${<hbhEHb6k`xzSjE8b|9=A`BV$8@!-5415)u*)8~~yN4h{;6KUo+V7}ywe7=Qqz
z)`2-eV%MEqH3oqrb3#)(Pd+%P*wdPnDf4t``0KcXzs}|TNqppyS)En9IKeT1A)?Ko
zzwtnh)%^3)xl-LeO)8hJUYZyd#eKkW;+JPSQ(4z@TTOSHZIm4qZTXIGY2tzRzyH^B
HGFSrubE-b{
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..84411068b3eb600f50c8963b03a381f9453a675a
GIT binary patch
literal 226
zc$@*^03H8FNk%w1VGsZ;0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui01yBy06+t$7`n`N0Z1Wbsez1WgDJr!Wm{ze)TnVlA-sYJknCyFm3-nB9Am3W
zY62_~Q$yYhHB=dGx8Q`4l%lTKnKkxu6<Gzt>+^-S$`+H1*Yd5U%VpH)^8K`f17Xka
z_n&535P@h}J6mRK6i9_*FoggHGc}5l7gd0DI+a3=RFEc^ECQcSqgbLs0%CG_U~Xsy
cI&&OxO|DZ7DQtl>4ZjK+4+F%-#>NQ%JAc7hZ2$lO
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..cae473e2211900f54233335317452b67c8c8b13a
GIT binary patch
literal 206
zc$@*w05ShZNk%w1VI}|&0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui044ws06+ti7`oj4@SFgupcRx*>MmDhC|Mw6RX_|Fa0zfX!hzw|7DpR!xwfdF
za7YBGSjD6gb!@$Qp%U#AHJ+Hi3`htPbTn6R#v42y2<WtW&2GDq%Q#Ur(ZXULyv6Ri
zlT%qaC?6g=3LRA@Wq~($H%v4D20Sf_Sa6RhGZ!{d8<k;zm~y0|5T~f8D-r{(uCK7M
Iva<;QI~)E@WB>pF
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..1fd246b6e30ba7fed551257263515b79ef231ce9
GIT binary patch
literal 209
zc$@*z051PWNk%w1VGsZ$0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui01yBq06+tl7`n`N0RW+dkT{SLXA2jgahSmv+16ofN_tH=cEtjig)~cb4)i*e
z#4-uFRxQ>JQ=lk(%cf-t6&5EbrIly#1z$u=IO=UJoebILKxn()?^jX_;ZD0>TE&=W
zSr%1bA8K+<J_3Oq0w^X1US}6!M|O9KB`1?tVuX4=Kq6Z|c$q|!eOIQSFH)6xAFpc%
L1GBWXwFv+_E>BES
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..e26d03694179340a703f3b8a514eb8fcc593fded
GIT binary patch
literal 221
zc$@*<03!cKNk%w1VGsZ)0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui01yBu06+tx7`n`N0mv4_BqPpdLBN_MbV6}uk_U|G8Fpr2dSEInW%{9#Q57K?
z&oipzguzy8msGlRD+>#08(C+}Rxx0})||IaHdXLdbYGRnuuMDALy8!4AlUDC{P2B&
z@Y``wf>aZNQ)7RG9$Z&XEd>HTb8(DHh<}%53LT1)K!8mvXNp_~rU71oYH%-BBdH+~
XGL~r(Q>=+D6uWc>1HZt*!3h96iM>?8
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..c23a6bd1be198d9165edda2a68d2498a2898f31b
GIT binary patch
literal 267
zc${<hbhEHb6kyO{*v-K3|9=A`BV$8@!-5415)u*)97u3*P&jblz=R1N4A_9;PZmZ7
z26mukAOM-+z_P>Ogy&03#tcOsaVY@-=WUD%QhlirHBK8REt6`OihjIDZkdhXTXusJ
z4f}i#6rbiTY;p*`;nZlcce$3w+F1W{tBxt$Qe`x{?(^r@lHC_p6vkHTZce)LajuR+
zLXCf*sHP4(OGjr{S5AzRguRGIltV^|i{|8<hUwC|`g1e9Ss5FX;-d?sW#t#<$}F>%
zS-h}l!$Nzxtv(gjdK>L!*@_e6)&zS-L|B{*pSo&&-civjLMr0SH*ej(Ey!RE0P^cx
AS^xk5
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9ed3fa82b294dc727faf5a50811288f9010d8227
GIT binary patch
literal 137
zc${<hbhEHb6krfxSjE8b|9=A`BjbVv3lb6%8X6o997s5D;DCdJg5pmWMg|5p1|0?<
z0I79g_LJCkCXMlgXR3tKwc5=(E*fHD%Y4<d^6vbS%~{^)VlYiEz?>zI=fHx18ObXZ
p+`8Ue-taJ}JuY=+w%5uPVSQ=b6B%wSS>t)khULYUsJRRb)&N_sGA#fA
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0f565549856e7a5772a0980e6e370843f55c279f
GIT binary patch
literal 151
zc${<hbhEHb6krfxSjE8b|9=A`BjbVv3lb6%8X6oN925>5NH}odfZ|UUMg|6U1|0?<
z0I79gj*-}PrkwGFXR3tKwc5=ljDaEyjuA7=R%Y)i%!`y@kXRI#+or}_BIWe>+hG~D
z6H9_-R&Q09?9>oqC0eX@QlmQ5)81u)%Z&|PnmTiiZ7>$BNnc*&VJ^q=V^7?C1_o;Y
Dw4XG)
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b0831f515b06ff70901c18f50170a7fe8abe5daf
GIT binary patch
literal 149
zc$@*10BZk7Nk%w1VGsZm0IC20|Nnpi0Rf<(pkQENfPg?iKp?=tV8Fn@A^8LW000L7
zEC2ui01yBa06+s;7`n`N0mw;Z7$VkvvouRV1crra6PlhI#{xtF$TMMjfI*BqQ34&!
zs9^(Q4uhm}xx}?rkjZWqC>n87VKF!<`~tMAuu;9KfG(VlxBI@HX0rTv5ZLc{d;$PF
DnhrP5
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a15fcf0ca71b8a6ff2965f0d88c91b3a8688cdbf
GIT binary patch
literal 145
zc$@)|0B-+BNk%w1VGsZm0IC20|Nnpi0Rf<(pkQENfPg^2z+k|@z(7DCA^8LW000I6
zEC2ui01yBa06+s)7`n`60mumo4MRlACDszr1caAu6PlhKP_E!q1oOpKgqRZ+@NJ^T
z>th%gk4R*!wSq_rJ6-QLIUGE;<x`Obj)u2Xhl<nXreUV<G-_uag1CG>PXGWrC-F8)
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..6dcf6e076f6a3929e162a00af80c70faf7c0b440
GIT binary patch
literal 148
zc$@*00Biq8Nk%w1VGsZm0IC20|Nnpi0Rf<(pkQENfPg^2z+k|@z(7DCA^8LW000I6
zEC2ui01yBa06+s-7`n`60mw;Z7$Vkvvm`_jfI(ql+LWs3#<c)(%+f)e9#D{Ah--w#
z2xk}=k4R+B#ezt7F@@>(=~bz^U?gy0<+O|&ptBmka=Tz}N@h~X!Z_w3sN3)N1OPi{
CH9OS+
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d8d69b9816f2a76520d34ad038c285a581fafaf9
GIT binary patch
literal 149
zc$@*10BZk7Nk%w1VGsZm0IC20|Nnpi0Rf<(pkQENfPg^2z+k|@z(7DCA^8LW000I6
zEC2ui01yBa06+s;7`n`60mw;Z7$Vkvvm`+g9AIH#+LWs3#<hS*9AtQUF#+m?33M7z
zgK#qpj>u#Z=VC!7J<*7T)BQfgA1roQ__WnVAPcOlZkmE_tn-zdRI$AC5ZLc{d;$PF
DDr7n~
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..11928ffdeed8faa3858a030e34e011e3e1ae78e7
GIT binary patch
literal 204
zc$@*u05ktbNk%w1VGsZ$0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui01yBq06+tg7`n`N0RUlyr9uWWqLhW86dLD!=(lxg3#?~hC<a-wpR8oJXHA*k
z%al5)h%OXNLP1q}NhJ~kl;VB`l5ja`1bEz#=wjoF8eq<Wz;3(UxabffhXM+L3MEjU
z@|bB?UV%m*V|F@JM{#>!R)vOrS3#6^KbM3c7i5-$b}B7l7GD;UkfA1Cs%i%VuCK7L
G2>?5y7ENCO
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..7fced1a7f5c65f57da1c7b9e0f636adcffa328de
GIT binary patch
literal 152
zc${<hbhEHb6krfxSjE8b|9=A`BV$8@!-5415)u*)8~~yN4h{;6KUo+V7}ywe7=Qqz
z)`2-zV%M28#uJ{Y3d+}NH;XVSu&`du6rPpzLQuv*u;su{*+Y%osb{@dFYsL1+$m+u
zeas=lYQF#ZWkroOX%RDmxP&f-#i*RM$m*$A<Fm40`nYY?O8w?F`n=71>h}9HFjxZs
D7>PB}
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..15abcb58f9bc1f2c54b76ff2feb5da413abfcaa5
GIT binary patch
literal 198
zc${<hbhEHb6kt$eSjE8b|9=A`BV$8@!-5415)u*)8~~yN4h{;6KUo+V7}ywe7=Qqz
z)`7WOV%M28Muv+`6B>IgUbEg*V?3JCBvn3dVHH=rwkX$`Ws?dH)O2>KiMu5$Nc4NC
z6o?)%%(eGxye_S$F4F4n_G`_K3+s!$R=O3-t)6f)wa-YP{Bu@Q(aAk?qyCkpNgDbY
y*GJcx##P6LFts`)n)hX<N8}|;%9TiRND(vW&7QSjg6I-Oe&!V`SFPe?um%88D@mRJ
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b9b982fd6c65803f89d0429272ffefaebbae1e91
GIT binary patch
literal 126
zc${<hbhEHb6lM@$=we{_|G$Bekuf15VZnk04Gj+e|NlR5AmPA)1ByRc7#SGY8FUzc
z0HoG|*;!)OohtPPPv(Ud9g2n<?ky=y)XbavvNyA|HOE8ZX$42cy7v|<*EMzYusI)$
ebBJe~X}E5N=yUy3g%RS?ClXG-t=i7XU=09hf-u_v
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..501cc280b92bcca8548f113d10da902c58b49347
GIT binary patch
literal 238
zc$@+501^L3Nk%w1VJ-j=0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui04@L!06+t?7`oj45S|kN2trf~v^9o>Wn-mWLbq`uF>GZf6k28kg(ZOcd0{G9
zs`X+SkI1Bw6L77T(CD#QMAb6E9S%^a?6RcPb;fk+3N%*Qf=07uDL0uWEDsKZynfH`
z`~QDcQiD=W6lZi9XhJz0WL#K~If;=MW>!xgB0~lmIT{#UK$=EWFkx6VH;x#qH3~Ig
ojh0m<ZyQ}CtR5$$BbBCv!ce9W#>dE169df6&d<=%($Wb4JH4)3+yDRo
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..e17b5ac2a62489f18ddfbb66e08328f9c8675ba6
GIT binary patch
literal 182
zc$@*Y07?HxNk%w1VIBYw0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui03HAk06+tK7`oj4=LA4O5MnATfH758S;R0^S9U605g39I6k|}HW3KO%ZSp{%
z568)1Fc*&SHWCyHEt)fgq18$Uf_BU8dcVJ*_$p~WF%+m3a9sD8DCEVJ{8a2Hcn_&E
kDpf>7HAog3EiXtQd0}H?Ll2OV3s?sOmY0~Bnwtp#JE~GbJOBUy
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fc4c901492e4303cee565b2c6655ac2e0cadc0f4
GIT binary patch
literal 207
zc$@*x05JbYNk%w1VI}|&0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui044ws06+tj7`oj4@SFfZ5P|}uK(63beU%szgLY-cNM%^inpqJWScz(2@Bctx
zU>7VJg+xoN5U{;gGNmgd=nYe&f(^9Y`fP$iFKk5}2<WtW&2GD~$GCAg$$Gd|aLywJ
zY%zd+S1K`09#2y=JSIADP#ZW;fF)IjRAr7a6-<a@P?b_AaB`$RgAk~x5M~DhuCK7M
Jva_@a06W3yPK5vf
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d7b963aab5e231ffd40ee462e27205aa5120fdeb
GIT binary patch
literal 178
zc$@*U08Rf#Nk%w1VIBYw0IC20|Nnpi0Rf<(pkQENfPg^2z+gZ?Ai%)DA^8LW000L7
zEC2ui03HAk06+tG7`oj4=LA4$AY=lgKqypJS%aWeS7wA0hkc`0o^fr*!F=y~ZsM=P
zN5o0hd^7-|P#{#Al;-kSIt;GZtai)&@xG&+BsO(M%~B9f7k<G+myj97M!hx$kvy;p
g*DZGdLM<tLYhGYrNDqvS3snaKl9QB`mX`?tJ2G`eYybcN
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f6cee264b7a9e089a614b36f998f7a23872d1ca0
GIT binary patch
literal 267
zc${<hbhEHb6kyO`*v-K3|9=A`BjbVv3lb6%R;>yR4b^)5xbVP%grXwLh6V>qOPRht
z_X7tG$jb6DfPvyq7DfgJ9tIr{2V{l=%MODRo|?&w8O|n-QUW|q&q|{N`%+H`e%Lta
z*~B|LbS|yi_;UBOX8{^wV#bOOLOB*RsWH4^4#<qSIN{r=+f^H*nvYEH@v{zFA*L8O
z;p#oz3W*Gni7}}!7+SIg6j<|%3q5(5J370%s#=vLTBBOnxeR#yTiCc<^HLSlL+8mg
zaIj>yOl(;uw>&mTWUZHrTScAs?EG!%4wK#77kN)-<l4G-Dz`#qWM3?&C?n^oiK*wW
Ps)#e)ymkAwAcHjk0sUfT
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9a283b0ac38526d84071960cae560b9ab3c70c49
GIT binary patch
literal 186
zc$@*c07d^tNk%w1VIBYw0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui03HAk06+tO7`oj4=LA5503{S)shA&?Z5%O7)s-2XA$%A7v6YEZc&_hxVDrFW
z?Su;$j78UH6G{zl0umthdWou+qUk{BdcWYXm?$jw2ohXW#H^AE*fW_EMbe$k(X*(r
o8(&CGcO`Qj07or=EHZY4H)dr%Cl8dB3tI;Rnwy-Ro}UQ-I~eXq+yDRo
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3132291843af4d4c23e7c7abfae8b8dd067743bc
GIT binary patch
literal 210
zc$@*!04@JVNk%w1VI}|&0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui044ws06+tm7`oj4@SFey1sDXux6PX-WFi?51ND)WVPF<#T!Fy}MF^r7>;FLC
zDHSXlO}t7ElWQquFO7{;+7SykT%kb1Wx17ab~HQ?&gisy&2AHqaNubI!2WQ|Y-WrF
zV}>eA7&ZZ1D=RvGBUXVdF*8pBGh8({Rewn_99TUu9+OfxIa6dwai>Tr5UZ>ZC=vs)
Mva__cwzmlYJ2Hk!xc~qF
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3cb24dfab40b8b159dd592f4ee67a991ea73a5c2
GIT binary patch
literal 244
zc$@+B01N*|Nk%w1VK4v?0Ez$r|Nnpi0Re!3Kww~CprD|@z+gZ?Ai%)DA^8LW000L7
zEC2ui05AX$06+t|7`oj4Fotsi5Ef_<#0G}3VOOS+pi*i@P;dibp<7@Gc+uX5TjD_5
zY1YArV6u;L$!t26ftcw@tu~`cn#Km?c$64m0n-{2YaXm+EWQ8*FE^a^hJOKL{JR!A
z4E}(Df`f#GhEi6EidzE}dSGvHZF+lmd2Bd*SyNsgAse4s7(OH@Wk_cqT$vpuDq%S!
uA*Cj*YCky~H#s{vLa;$BuSG(ri^o)I63fiYeFp^5($mz{*4Nks2>?5fxn79?
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9c84f46b90bb99c9c42ee6370cc0ded92e8c8d5a
GIT binary patch
literal 143
zc$@)`0C4|DNk%w1VHN-o0Ez$r|Nnpi0RdoOV4$F&fPg^%|Np?iV8Fn@A^8LW000L7
zEC2ui02Tlc06+s&7`ohjCx8ivq#zKS#kiBjX`=^nC>EG$ORXO!s+-DE2B8y1)!T!E
xU`Q+)jWJhi6~W{<yiziB%G6#r>gYOwoh-W^30PHPKaRA+0~xsA@OV4{06WS}H){X@
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..1851430c25d38d7a66bf7e8a5654fe12886cf88e
GIT binary patch
literal 187
zc$@*d07U;sNk%w1VGsZw0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui01yBk06+tP7`n`N0e~W^Ei#Z1rM=nK2~8k`oCFv_5f~WSsf7WnTB`0voF9as
za5&UWb^@Phw=ytuqtXcgRk32bDuC3OYMEQ_68s#KaRi8`HMz=mtSMT@Wr&Su>X>3t
pDDf^%Sz~nzcO85me=~VsOcifrka{|aAe1GUKL-Pyo}Zry06TNnMl1jT
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..722011fc5caaefece4661951121824b779efd103
GIT binary patch
literal 248
zc$@+F00;j^Nk%w1VKM*^0Ez$r|Nnpi0Re!3Kww~CprD|@z+gZ?Ai%)DA^8LW000L7
zEC2ui05Sj&06+u17`oj4Fs^d~0K(oIgfLsj38AMM3SfX&wgJIFXztq;f$<rIsgs=y
z%Z1aS3O1SM#cVpCP-bivty-^B+H!=;36P^w2G_HQp4m&!^TmMKuXd}@+tgbga7cC-
z`2T=`f`f#Ge^ghAihC7mByn#Zcx*^*j{tWVc~VL(TQDXeC1MJd7AqU5dx$lom>&UP
yXP_=CE+QEzt6G$xMX<7$K^k3{UP4KTi_2A663@`lQxpW%*4NnC+S}aL2>?6Ku4lIZ
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9afa0690e66fb68e07b77b1cb2309c0c58d55df5
GIT binary patch
literal 188
zc$@*e07L&rNk%w1VIBYw0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui03HAk06+tQ7`oj4=L7)6R3M0IgfNpujTtda6_#mZU=)<)xl~}HWUlY^&Hq2!
zDW>trD4h&UW-;`JfWoG*T#~3#o$x^DdcWYX7z!-62oj2P6BWSJ?6&a?wP*?oHvU8G
qm+BgMEEydvOmRXeA{Z=#88ccwW|N5zmX`}A5d)l^o}Zwh2>?5Fh)P)i
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..55406887839deeee4c579141ffc25e07a0cebae7
GIT binary patch
literal 214
zc$@*&04e`RNk%w1VI}|&0IC20|Nnpi0Re!3K%k(YU|?Xtz+k|@z(7DCA^8LW000I6
zEC2ui044ws06+tq7`oj4(3k*#pb7+GY3<dKUEfv(#Nb_?!d*ff2S-JcC#R*}=l{T9
z5Tz0tk3*hqBQwEbg-an2rQkF=q9+O{6fEDUOu(&_EioU_Kxn()@VI<lMB0z2i8<XR
z_s13=TxWhebu45qARjDWH$5hXD;q9OOk^Yn2ahFLN+21QV>nYSn<6EjcdI{I5U;Qh
QDG~#<wzs&sy1NMgJC%=77ytkO
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..bf142db3670266ec87046ae4d8e9223e639e7203
GIT binary patch
literal 202
zc$@*s05$(dNk%w1VGsZ$0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui01yBq06+te7`n`N0Z33xFk%KWBF$5{by6XmXd#VW=mM;3Dk{u*=eyog?t`((
zX;BO6G(3O+qXg|prDJf3Iu(<@=F?-U3a-$CA}7K&0zl4zz;3(U(Blqr{B9=|g`pfC
zGm&v20%&(yI#Xw9P-HJt83ih2j#`pt4T>#th?j*WgEWPojD=lQU}vZ!4+E^NuC56H
EJ2{X|6#xJL
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..742c9f0053220c3c7e433b086a2e746e52883577
GIT binary patch
literal 337
zc${<hbh9u|RAUfeIK#m3|9=Yu1H;m#OOun6otzZ6ZjCy2ELl@iKtO<_rNv26QQ-OW
z;$z2-85&9~T^e-lTDF&$VsWu$a<XA|wqZ|?69XZj10q0nF|b}sQ0Pm^oTqV^#o_h7
z0-fUrH=L``yUvu&!W({oA;QC@-KpClONZgiMBxL;qD&m_*&G%r+!Gom6&Q$cad2#@
z3G-OdEcak~K+f5u>kk=JUtDFW^R5dmX5@|xVH4ER<J4i{Xk=&P58&by?BOgZ3TG(o
z>epY)GGiu(aKI!EMv>@3JDm<b=Ws9G>e{{ub^IKTb2sUh#>DX@RHme{vX?dLmK<W3
z@4D8-Z7uJPK#yq`bcLt3T0OOV^6aHSsK(oO8ihQ}pTB(l_Wj3CCM~AF|Nb*DbIC|B
HF<1it69a9g
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..65fea0a9491d77ede46997fb49eeb9e4318af8d9
GIT binary patch
literal 279
zc$@(j0qFimNk%w1VGsZ;0J{JH|Nnpi0Rf<(pkQENRaGjgs#V9wV}O7_a&kF9Kp;6e
z9KgW9j*dqi9S-B;aR2}SA^8LW000XBEC2ui01yBy06+x9Fvv;iS^;Q4Nb6fL2-#LB
z2(bYoxvJ{gmVgl)N0Njiz5cTmVpu@%T&rS(ar6-!if40U!|A3!+fEZS4HX8gMrDk#
zdapo-$wgBO@NgTMM2P{64uO59*Wd+meKbBeb3Q*}T8S+S1CNlAk$#D77%u<{9CrW(
zoic7?n`T{=cLoG%f~6d4ft;Oohjl5SeyDJKtS~^KHI=(3ud^#Sf`cJ~2?xY1%FM{c
d2gjuqH_aLe0o0+^&@<NIBNqbY=I7@T06Wh|Y&8G?
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..aa904093112c5ad8552337b768e7db12325d476d
GIT binary patch
literal 233
zc$@+002cp8Nk%w1VGsZ;0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui01yBy06+t-7`n`N0Z1U|l!1&mS;ZPB8HQkX;YA6>m2GMaydqGVEeKC0j_xB#
z;WJBNa<&gmWe6aPK$)&abQvW*)~{9~A(uQ>4U82uzt{4U?3|RQordz-2+Riuf_~5E
zN2M7M7gbvqH(GFRZB|iTh)`5LXi-A|1(Q@3j5UC1L_}nk3I>~o1*D*9l~rT~c4nlB
jGlO>`t|lafQo0wev5*tKF`=Csb;lYH1Ix_K%?SWI<ds&)
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d995bf4f7f78d89091cf7c0a82e9864fa5be44bd
GIT binary patch
literal 237
zc$@+4022R4Nk%w1VK4v?0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui05AX$06+t>7`oj4FotsiD4~Fxh24QC03P{mm}YK3$hO4r8KGyGf<V8en2)qv
zrXV!rK(W(n$!t2GNEviWod%LCR;^~Zv3fNDQTcLdv8bGi_*4DTztKg_Q$-JiynfH`
z`~QGwRfB|A6)bFPaZ5yVi;iw_Dpyh|C><XqUly8|ZYO3@oJw0cGzF+DK4P60T5_Tr
nK{hx#n6#@vTXvx^QiQ-%loG_n#xWEF%FE2n&d<=%0|@{-6TV{w
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fd8dca3505db6220c29d4b12b5ee0b0c87166899
GIT binary patch
literal 169
zc$@*L09OA;Nk%w1VGsZ$0HOx~|Nnpi0Re!3Kww~CprD|@z+gZ?Ai%)DA^8LW000L7
zEC2ui01yBq000ASc)HyFFv>}*y*TU5J0w^jjwGoBK&q~3FdQhG3PL*&u^iNZi_0yZ
zFUQ*1egHwq*t^9Fw5XtPBtoaFp~^rqsI-7WfEpfGXFT*dnP#uWWcV7u9eL+r8W|64
X;+B9n2LptKhK3*q1dEJ~jR^odmsUY|
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f4f03fdfc01aa9995620599239b59dba1e5c01db
GIT binary patch
literal 246
zc$@+D015v`Nk%w1VKM*^0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui05Sj&06+t~7`oj4Fs^d~D4~FxK@eN$ft<E|f(01HNs0k6s0JFeo*~pifA=d}
zE7hxMe#VnbC2BgK&}cI@lUlD>swD*jAv>cDw@KV}z9wy`&@%x9?hstW23}qT&3r05
z5dMIHf`f#GhJaOAii;sJ6>DvBJ#&+hcXoA_m2PSnCZ1uT9~+=0V_~DBOK(i5I(wmG
w3qEFzubitvJ~*jeAv|VmDi~fbjk%1;R$3Cx&d*d71Jl&i*4NnC+SCaEJ1-AnDF6Tf
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ec419c97c1d87fb677c47ae5971389fdb164c5ac
GIT binary patch
literal 236
zc$@+302BX5Nk%w1VJ-j=0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui04@L!06+t=7`oj45S|l22?baTg3w_1Y2KA>g-`*8LK4H;3aUXG!b}JF=dqp|
zKsa0lV5^XF$!t11$ftDbJjRNlA1}udfr3eq%A|T-H7UVqxCW`+r*wQ|8Ceg6ynfH`
z`~QDuRD)DU6d-bLG;fPE8E<uvLx^@!CTJW#UYjD9C@LIfP*<WPK0RxiVqst`I7U%G
mJ2sqObU!*gSR1f{guhKz5yQmA3NRA`%FE2n&d<=$2>?4Ps$CKQ
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..1c94d0681f91da909bf71091683b17a274afcf55
GIT binary patch
literal 136
zc$@)<0C)dKNk%w1VGsZm0IC20|Nnpi0Rf<(pkQENfPg^2z`#I2Ai%(2A^8LW000F5
zEC2ui01yBa06+sx7`n_=0RTcIl`;$wvG*GHjX>Cun2CbhX($ydP6lPv#8I|ux)p<<
qa5$XxG>~3~r&LV>lz`4RyG&xsY6G@2uAIl#cKj;{&ggVH0RTH(*fS>p
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..812b722d810b250025013e55a66503647ab0ea38
GIT binary patch
literal 197
zc${<hbhEHb<Y!Q3Sj52a|Nj{<m^pK18W0#88#90e|117vVPs%nXV3w189-_on7bl&
zt@+M+!qb~W;Zp1gj$3A$EE-{RE4`NN+V+rheU4POvBH}@6K+~H7i9dHn#a_nIO(z`
zx834bl51s~z1vKbBr5hdzg?*<#@Xe2YUiHF^XFU^?%@8msaz((&BGz~d>mV7zAHnM
svO~Hx8*@cVVMdj$O^%Tn?+i_LMwXe}s<Y?Lo5je?vV6r#c}@mv03bC<_W%F@
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3173a5ba6752624239cfd0d49320f39d8cbb7ba4
GIT binary patch
literal 164
zc$@*G09*e@Nk%w1VGsZq0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui01yBe06+t27`n`N0Z0=>sS*S-A`rqCW*X;dD41<s2EN5=lC<1PVOWgiEyA`_
z<P?-#6fqLZBWPfH2ZD4;rTS_z$STEKu9^ZvcZOAxQAo3|Qn3_`ZkqRF0Ep$}a9A9l
SmnBP1f*cP6hKGoV2>?45sytl)
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..aa9502feb225a88c993cc7a6b0c6691698902a71
GIT binary patch
literal 232
zc$@*~02lv9Nk%w1VJZL+0IC20|Nnpi0Re!3K%k(YU|?WCKp?=tV8Fn@A^8LW000L7
zEC2ui04e|w06+t+7`oj4kew3%2*O%X1g{ui1O~u)1?XWybrFLbbZL1N_PiF_oQEwL
z%%v$BkH}<isBAiu0p{&f>Rd{?77t)0U0PpZY-8IL4F*9ulhL5nCQ&;&I1ujmynfH`
z=f_WhPf-*b9&i?E8iyWdZ6=6~FMuImA{bkhV3!;g3tS4GQdv12Av%>)r$HEEGLM#?
iEo~{WVJj=5fP%b8bP>S8z%Ua7#>dFX%FE2i2>?6UTvx~d
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..14d4ec20ba46d0854e1a800c028ff23dba76d612
GIT binary patch
literal 143
zc${<hbhEHb6lM@$SjE8b|9=A`BjbVv3lb6%8X6o997u3*P&jblfZ|UUMg|6U1|0?<
z0I79g4w2Y(r%Jtn(@W#X1n<KFLaY*u8zmR9cjc^Z%l*?8?NuW0ljxGTK=^8+gN{`H
vkx(DAjx80e*K&@p3}L+Nxwe@5S;UearLVEOiu%4hViw$S|HBSzMh0sDSr;_o
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..4ce095c6f7505cbe173de0a3bc269ba7f72c811a
GIT binary patch
literal 139
zc$@)?0CfLHNk%w1VG{rl0IC20|Nnpi0Rf<(pkQENfPg?iKp?=tV8Fn@A^8LW000L7
zEC2ui022TZ06+s!7`ohgCx8h^p@C2khLDsI6xOwM-=?l8xW4Tsj)bAcDxtI9G5o-w
t@RxeQ29cFcbMv?=t|!O2GFSpO3^hb6U{70P^W!KldIy1e&2Fm`06VU#HcJ2i
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..e3b501c13e5892bdf173803099b7dc712afa94f9
GIT binary patch
literal 232
zc$@*~02lv9Nk%w1VJrX;0IC20|Nnpi0Re!3K%k(YU|?WCKp?=tV8Fn@A^8LW000L7
zEC2ui04x9y06+t+7`oj4(47;2C?JQ6wGb6hbQ@4+=&2DyWdsEWyzyvlS74ZeS>vEs
z&%_F$j>x2Pi3}8(&?wZ|nkiyCRR;7a=y<-|4xD;!KgZ9|Fr4iK?{QjA92^MvynfH`
z`}tK;f`d*JC~9eFGiq>KZ)%T_D^(yVA{{)H9$+V(ZFNR$UN3EL8(t|rFduSSR4%Kd
iG%}i`oS&OzfrGqEuMxn(!7LL4#>dFX%FE2k2>?5f#9r0_
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0d32fed439b8ad650a0263a03d1535f2a538c844
GIT binary patch
literal 230
zc$@*|02%*BNk%w1VJ-j=0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui04@L!06+t)7`oj45S|l&FdzpZYPR0DeSm>!Le`N1F;qohTv*55p*C|xJe!uw
zMo<8>UZkXQ$!v;TIj3}*Ji-*SqK&s=?NTFUR|EarGKCxWrd1b%sZW~aIuP#oynfH`
z_mNbAfh`nf9B67pafWOvhX846WJqHbV<1(FB_~F4msWB@X+w%pGG}3sW;vifqFXqP
gr#!AeDy(IKx=vORzQ4dn69dG>#>dFX%E}1<JK|biA^-pY
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..dd739297582702a50b6a69549518664cf17f8607
GIT binary patch
literal 222
zc$@*=03rWJNk%w1VJH9)0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui04M+u06+ty7`oj4P@NNiFdzr9x!~I8ftgj6KtK#t5f~Sy2<B-Sn2D05%A&xa
za2WL2h{$Ab)l$F;DbVKRy6H+h4HNsx2%xk=7>X5(3g!>gcObam@VI<VcmI@lq>93&
zS-xI=USwh@g(yZ>DJcp728|go0boa2DO(w0k1iZDCmxTAqL)7|Fq<8ziXI(bBY=r{
YvPDc0wzm%}69c@xzQ4f1!n_FpJ9-RQfdBvi
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..bc577ab80142c8b2e62c72c0688e3ad6f3026777
GIT binary patch
literal 215
zc$@*(04V=QNk%w1VI}|&0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui044ws06+tr7`oj4@SFguFck!GxuKg7Qksxu0Wpw35f~R%y~Vr%BKclHt*NY&
za7ZlvR>q|AltNZqJ0DC_+kiwf*vHol;y9L5p&+Q4$QB<{bs)Ik@VI<VcP{V5)I`WJ
zWzZI7fq@)qT^U$2Pa84|03SMjH%DG%TN*GoRtkwbf-^vWJ6n?_BOH-Khj^@OD-f`;
R5Nrnnwzs&sy1Tpy06Vs{QZ)bo
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5ff6bfd92f9eea7c60098b6c7d4a615bd6b0a487
GIT binary patch
literal 207
zc$@*x05JbYNk%w1VI}|&0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui044ws06+tj7`oj4@SFguFckzLXx3cEd4}=@#NYu%U|g8kVE}Bo_nEF=@Bcu}
zE=VluRGF4bP^fKYEXu{%Ds+y#8mD6Y6q*^PAUV#U1_y$A&2GEjaHMe#L``}jZm4Vl
z*T`65D^ea;051Ve9f?kXUKfcnWg;bw28fPPFC|tyhE9e`nRKKTXAr2Vs3{TyuCK7M
Jva_@a06RAbQGfsd
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..316750a26bc6d8986c8ee8ab8018e02d5b468766
GIT binary patch
literal 235
zc$@+202Kd6Nk%w1VJrX;0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui04x9y06+t<7`oj4(47;2Fdzq^xvhYK0UOB`LGfiQNemTgTt*=X!F+F5YW}j%
z?WTEwTF9hwxeOSY&?wXi1E6vORVRbH8GNN&j@7+ssmEa}o3XJ9DmI&I9THuG17Xka
z`~QG}e^pY2hE5b@cXnAeLt1iLaCLS?RX8k1B`aHDS!0|nXm34d9$jCV911}~W|lEn
lU#46jD66;`sbzPghQCur5yQm9FB1dF%FE2n&d<#W06U;<T@wHR
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3d97c4a3003873c41cff132c1d24988a563452b2
GIT binary patch
literal 220
zc$@*;03-iLNk%w1VGsZ)0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui01yBu06+tw7`n`N0RYj0kb#USyT=+QTpzeeBVb%9ke$<26tT&b?Ryu7HPWsS
zid52-io&DESWD%SN}HrGs;;Dxo&gD?Dw&i9iKz+{79BFWm)0Bz@VHzKiv}TftdliP
z?rT9^RaHP_A5V3MeK27Riy~%6hGz?pQvn7*OG#dmek+58encN+KvbGwTLN2Gfg)Rx
WuBHMswQU;}x^4#pzQ4f02>?6yxl(EX
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f03a4805946be365be77306685577d31c80a58f0
GIT binary patch
literal 255
zc$@+M0093-Nk%w1VKM*^0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui05Sj&06+u87`oj4Fs^d~5C-TVcE1*2WJOSDWg&!yB4*mU5rb74n4zw?u==f2
z%NNM-Vzwg2G^=Tz(5Q4utu{l}tTr2<C6y-+5@?b=IjfY6GwnKKKByq9dKTzDy!~^@
zpJ@jKf`f#GhKGoWgKt}njx!ZcJ|B~LJANpb7kiSLZWd+$SZp9?b4&ng3MVonPp+a~
zdqH9#OGr>?79(pND=x84H%nopW+fd%N5?M1N5NQ+(pH}m*4Nl>6a(Dd-rwNi;^W;3
F06T}fW;p-=
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..775438137516c30600bb55aea095ea04b0435662
GIT binary patch
literal 183
zc$@*Z07(BwNk%w1VIBYw0IC20|Nnpi0Re!3K%k(YU|?WCKp?=tV8Fn@A^8LW000L7
zEC2ui03HAk06+tL7`oj4=LA4Sp&$q`spgpG5km(UL1A5>w|#{fkS1o|_&t|-?~gnR
zDkU%gTAA0TZ~@ki8{0-8oEAf*17XYUdcWY{Z;X}Prd3SQV72W`$VvQFk<o7K7+a>a
l1dJJXLPUBQDltbee@<kLfh7--k_%Y}1DBYYnwy*n06RzzN5cRB
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3ff912b6e50ba6a42bc32739d435e9092a62803c
GIT binary patch
literal 181
zc$@*X080NyNk%w1VIBYw0IC20|Nnpi0Re!3K%k(YU|?WCKp?=tV8Fn@A^8LW000L7
zEC2ui03HAk06+tJ7`oj4=LA4Sp&$q`sm=n11;o$+Mo?H6H-@Se7+!gbc&=ym?)xMY
zCKaQ(Jg`+^RuhUgAq-SX!vzn7tai)odY!-Uh#<jDQBi=v2(9wK$Bg>)`GA@?^wJQo
juhwH=DN0N+OGr6Ed162|508)wB@qLamY0~Bnh5|qRY*pg
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..1000a600a9758b451a2eb925449fce9d1db3549b
GIT binary patch
literal 230
zc$@*|02%*BNk%w1VGsZ+0IC20|Nnpi0Re!3K%k(YU|?WCKp?=tV8Fn@A^8LW000L7
zEC2ui01yBw06+t)7`n`N0RSVUwSkOyyUd&Cft*l@;6bcx+lEpR6r)z2lKI&=4(I?<
z?^gi|iJ~AciCIo$CV^oG1IQLMYN-)89fJjvtXZ9jIZBv;A?RvzT<@~okXM;sJOKiq
z*6wQyb{uO3eiwNZQiyW_ertn67Dh{oQHyD423Lk;C0Q|%KcH5kPYRuHJ)1M0Lpqc&
g0$~NTriUFzK!2Z?m`4;zBwWNA4+F@_%E}1<J1KTnBLDyZ
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9ab320eb9a62c9872bbd343d7a6673ae28d5aa79
GIT binary patch
literal 216
zc$@*)04M)PNk%w1VGsZ)0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui01yBu06+ts7`n`N0e~W^Ei#Z1Wi3WvNPxzXpfZwXCp3YOZLVAacS(~xF6$?p
zL0}jTXTjd<*XlWeohNJOtLB=|EA`c2Zf#&>REdE~3JT&+>{<7)Ij8ABsN3)Nq*MoK
zPcT|RH-lb+Fok1MSWbZ*6c%c1dy;4iOOk|DW;lnEC|qT5M{%2HAxEBNa$kyDLy)0V
S6s;UEwi^!vy1Tr*2>?4bn^c|v
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..8c905a62681aa8231ec3203d67009db5c0e1cb8e
GIT binary patch
literal 148
zc${<hbhEHb6krfzSjE8b|9=A`BV$8@!-5415)u*)8~~yN4h{;6KUo+V7}ywe7=Qqz
z)`2-vV%M28Mh3+tON=H6rf*$vtdTXeCAz(FT82P@&S~ZB?yLeP*AEXT38n5}_LJJ@
zbE+)bC~$)MDmDuPKHcZ9K3!JYeI<7Dwp2;h_Jy92+O~x!empZ=ar^yu76xkorQ|pw
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..7932f842898677e36cb01bea594e3afe29290ad1
GIT binary patch
literal 222
zc$@*=03rWJNk%w1VGsZ+0IC20|Nnpi0Re!3K%k(YU|?WCKp?=tV8Fn@A^8LW000L7
zEC2ui01yBw06+ty7`n`N0RSPSwSkN%O;Lq`X&m5zqLghCbzSR0%yeC|Q}wE3TU-U*
ziX-@0f;^nd1?%N@$r3c$Y6OH%(<cxbDUA{&U}!mUQ)6clh*ee$XzIk;Cer0od_Du|
z=yqfiK@=1zflPo|aZNa5gCAZ*e@|(RTojOcQ-O|{C5MwtoR>wPS$k>~h;l_mgNBNm
Ysj^>$g>nXyj8?oc2Lr&t!ompvJIA0_h5!Hn
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..7efa66c0479a33889db9d1baef515fb94679c6a9
GIT binary patch
literal 146
zc$@)}0B!$ANk%w1VGsZo0IC20|Nnpi0Rf<(pkQENfPg^2z+k|@z(7DCA^8LW000I6
zEC2ui01yBc06+s*7`n`60RYkhkzt4k%9S9daa8kVn?!t}C>TR5&vV+|C<p5M2o^UN
z>98sS0l8o+sq8@{p5p4r+~Is7o)9XXZYQiIw!}D%!&z(-IjXod4}pA6rzZdaJA;ch
AMF0Q*
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..1d1e887974fd9d2cba5421104aba342dbeaa1d86
GIT binary patch
literal 225
zc$@*@03QEGNk%w1VGsZ+0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui01yBw06+t#7`n`N0RYj0kb#US`?Q$G6+&qi;U<-ymkkFY&or${24i$D2Nb!$
zjwf1OSS&!V<s;sbEoCvvoI)oT=`AWiX-5iyA)DeLkJ;s?k)HCRYLcnsRa4kyYIUoZ
zLOgO_c^_T{AYVovNpW*@gB>Iabyj0oE^a?Lm4gL>Ka)>rmWUH$2BvL%dUh45O-gW9
bt&g6Up{taQpd(~^6~8YJ1H;6{#R&jAOpsP?
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9b73db72dd45fa921cbac2fd2ddc61ed35aabde5
GIT binary patch
literal 151
zc${<hbhEHb6krfzSjE8b|9=A`BjbVv3lb6%8X6oN925?KK!V~=7DfgJHU=FAAONX#
zV2+X4bta9GAt*!Dy-iWcqD7@ET3yWXBdcOSm5X)O9K$;m^JW+S_uA;G;QXk<&Q_{l
zC|juhq@amcb3nKEw6LWutxZA78xFo=N;TGKyc4we@SfM*KI<h}e(Z^x&%j^}0E<mF
A3IG5A
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..8d730e7344b6b1bd6a7330400a7009f3ce19f8bc
GIT binary patch
literal 147
zc${<hbhEHb6k`xzSjE8b|9=A`BjbVv3lb6%8X6o9fIxzSgM#8u7DfgJRt6mgAONX#
zV2+U3bthJ}fwN<Yg20^i9V~?zi4ro3q7~xLi(Y>}r_~+#q3x({!V8fm#%G#5eJ7R#
xX)Zn+Hu2>8EepA_&vNFm&-swI*Ju0WwJoMcHWeQ)+97+iDZy|3?YEo^)&S@oI$i((
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..75df2c018d9660fd3591e7f2e001e580f09028c5
GIT binary patch
literal 200
zc$@*q05|_fNk%w1VGsZ)0IC20|Nnpi0Re!3K%k(YU|?Xtz+k|@z(7DCA^8LW000I6
zEC2ui01yBu06+tc7`n`60RSOpr81BaXA2deaS~9JsJL}lnys!oc5ZR1<aAK{JxeVa
zEQb0KOGb<`l>9J<u9mS766S)bDX;gsI=i&v$UrEY&*$7x1zCe7HdGwPy4c@3!C|+<
zuZ>YpYAI4fR9gZ*Ls&(NUvxlKS&j{YG&fdtL`geaiaAu9P+}_|rW+3fs;jK52>?6e
C%uK`p
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2aa2a97c00e732613a6486704c8f2297e544314c
GIT binary patch
literal 276
zc$@(g0qg!pNk%w1VLAX10IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui06G8=06+uT7`oj4Fv@UF06<)<F)o2&1O>Nch9HbUAOK+5d9A9w0Wr8MU)(kp
zK%^R}N-YC2qzYwtDvrpL+tIGrtai)2R!`lqc-+!$W=~rQMDn1AxDr!iNFQOB73TYS
z^=)@Bem`zB1wTj`f`ErKI64Oel9QB`mY0~Bnr393o>(~+KY)vBNQi)bf^MXxQ5=bU
zPi|mILbDzqdNn4vG%0OmR=z+2YYK^POfE?`CTeLyvS`ICbwk%^%zMs5c~DKX!nL2}
aVP6yJ>gx@V2Ltf&^7Hid_V@S$2>?6)7jhN=
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ab6c02bea920825db9531cadcf2e85531df807ee
GIT binary patch
literal 135
zc$@);0C@jLNk%w1VG{rl0Ez$r|Nnpi0RdoOV4$F&fPg^%|Np?iV8Fn@A^8LW000L7
zEC2ui022TZ06+sw7`ohgCxAHvnMBechTa#DQ2^(WXlj0`+OcIgZf|N3gn^oe;Qzp&
p@6>8>BB<QtMq2G;EN2titdTM}OO;sMy&T|02Qny|&**Xj06V7gH+KL4
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3b6717a83b8e53528b82740dd93da4cc5eb53728
GIT binary patch
literal 154
zc$@*60A>G2Nk%w1VGsZ$0HOx~|Nnpi0Re!3Kww~CprD|@z+gZ?Ai%)DA^8LW000L7
zEC2ui01yBq000ADc)HyFFv>}*y*TU5yWc@5j-wI)XsV*YaGWbD2<$+>aX<s@9kaV0
ztS~F;YCeE~bmZA^KO}59+BuWN;<6x(&bq(vb*SBfsUoW|s#>$9%((3^sN3&%f`Y*B
I`~3+3JIpLZ3IG5A
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5ba1470c8d73952cc8d0e83c9d5f76504c77f1c4
GIT binary patch
literal 133
zc${<hbhEHb6lM@$=we{_|G$Bekuf15VZnk04Gj(l4kS1@C>%I&K=CIFBLf3FgAM}_
zfYdrLdr9oNQ>EVE>ABFNLot)HMKI>(wZx2*OW!P6n~^B-vN}xVmz>l4{|DsOEERT1
lV(~uP!nu><sAB4|O;;CqYhFw(st}hxk>H~@`#2|qH2?w@G2s9J
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..22cc35c18fc58ed591cd4438f83f4de9e9cd512a
GIT binary patch
literal 187
zc$@*d07U;sNk%w1VIBYw0IC20|Nnpi0Re!3K%k(YU|?Xtz+gZ?Ai%)DA^8LW000L7
zEC2ui03HAk06+tP7`oj4=LA4O3Bpt?1fPJRQ2{Z40JaHKHhP^A6r_n(c&_K=x&OeL
zZxv!$CK&)MGZWq{MhmSXC`1d>-hsgFdcWZCFi74IB-E)=U8Pt%Z6_7vsTe%8I?33(
pi7rzxGD;YOW@98OgmZcqd^Tl~DK-z4mJ22k1Dl+ko}Zuz06S3{MIitH
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..96f09f99092e56843cf258db571913502c6a0c21
GIT binary patch
literal 189
zc$@*f07CyqNk%w1VIBYw0Ez$r|Nnpi0Re!3Kww~CprD|@z+gZ?Ai%)DA^8LW000L7
zEC2ui03HAk06+tR7`oj4=L7&sFeVf+6$k>rQ6v=%!~|p%#;Hok37kQmX{qmgiL1RJ
z??<v|L?GG>NxR%oDnWs=*;J;|N@#~W48Gv7cudX-&%S|#I@NBrRjo2@{$M6AX$(mj
rnV>}qSRgSVOf+;V7%c`P9)^B8L}-*h50{t=C=mpmo}Zwhq6q*yki|rh
new file mode 100644
--- /dev/null
+++ b/editor/ui/composer/content/pref-composer.js
@@ -0,0 +1,221 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Stefan Hermes <stefanh@inbox.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var gPrefService = Components.classes["@mozilla.org/preferences-service;1"]
+                             .getService(Components.interfaces.nsIPrefBranch2);
+const browserPrefsObserver =
+{
+  observe: function(aSubject, aTopic, aData)
+  {
+    if (aTopic != "nsPref:changed" || document.getElementById("editor.use_custom_colors").value)
+      return;
+
+    switch (aData)
+    {
+      case "browser.anchor_color":
+        SetColorPreview("linkText", gPrefService.getCharPref(aData));
+        break;
+      case "browser.active_color":
+        SetColorPreview("activeLinkText", gPrefService.getCharPref(aData));
+        break;
+      case "browser.visited_color":
+        SetColorPreview("visitedLinkText", gPrefService.getCharPref(aData));
+        break;
+      default:
+        SetBgAndFgColors(gPrefService.getBoolPref("browser.display.use_system_colors"))
+    }
+  }
+};
+
+function Startup()
+{
+  // Add browser prefs observers
+  gPrefService.addObserver("browser.display.use_system_colors", browserPrefsObserver, false);
+  gPrefService.addObserver("browser.display.foreground_color", browserPrefsObserver, false);
+  gPrefService.addObserver("browser.display.background_color", browserPrefsObserver, false);
+  gPrefService.addObserver("browser.anchor_color", browserPrefsObserver, false);
+  gPrefService.addObserver("browser.active_color", browserPrefsObserver, false);
+  gPrefService.addObserver("browser.visited_color", browserPrefsObserver, false);
+
+  // Add event listener so we can remove our observers
+  window.addEventListener("unload", WindowOnUnload, false);
+  UpdateDependent(document.getElementById("editor.use_custom_colors").value);
+}
+
+function GetColorAndUpdatePref(aType, aButtonID)
+{
+  // Don't allow a blank color, i.e., using the "default"
+  var colorObj = { NoDefault:true, Type:"", TextColor:0, PageColor:0, Cancel:false };
+  var preference = document.getElementById("editor." + aButtonID + "_color");
+
+  if (aButtonID == "background")
+    colorObj.PageColor = preference.value;
+  else
+    colorObj.TextColor = preference.value;
+
+  colorObj.Type = aType;
+
+  window.openDialog("chrome://editor/content/EdColorPicker.xul", "_blank", "chrome,close,titlebar,modal", "", colorObj);
+
+  // User canceled the dialog
+  if (colorObj.Cancel)
+    return;
+
+  // Update preference with picked color
+  if (aType == "Page")
+    preference.value = colorObj.BackgroundColor;
+  else
+    preference.value = colorObj.TextColor;
+}
+
+function UpdateDependent(aCustomEnabled)
+{
+  ToggleElements(aCustomEnabled);
+
+  if (aCustomEnabled)
+  { // Set current editor colors on preview and buttons
+    SetColors("textCW", "normalText", document.getElementById("editor.text_color").value);
+    SetColors("linkCW", "linkText", document.getElementById("editor.link_color").value);
+    SetColors("activeCW", "activeLinkText", document.getElementById("editor.active_link_color").value);
+    SetColors("visitedCW", "visitedLinkText", document.getElementById("editor.followed_link_color").value);
+    SetColors("backgroundCW", "ColorPreview", document.getElementById("editor.background_color").value);
+  }
+  else
+  { // Set current browser colors on preview
+    SetBgAndFgColors(gPrefService.getBoolPref("browser.display.use_system_colors"));
+    SetColorPreview("linkText", gPrefService.getCharPref("browser.anchor_color"));
+    SetColorPreview("activeLinkText", gPrefService.getCharPref("browser.active_color"));
+    SetColorPreview("visitedLinkText", gPrefService.getCharPref("browser.visited_color"));
+  }
+}
+
+function ToggleElements(aCustomEnabled)
+{
+  var buttons = document.getElementById("color-rows").getElementsByTagName("button");
+  
+  for (var i = 0; i < buttons.length; i++)
+  {
+    let isLocked = CheckLocked(buttons[i].id);
+    buttons[i].disabled = !aCustomEnabled || isLocked;
+    buttons[i].previousSibling.disabled = !aCustomEnabled || isLocked;
+    buttons[i].firstChild.setAttribute("default", !aCustomEnabled || isLocked);
+  }
+}
+
+function CheckLocked(aButtonID)
+{
+  return document.getElementById("editor." + aButtonID + "_color").locked;
+}
+
+// Updates preview and button color when a editor color pref change
+function UpdateColors(aColorWellID, aPreviewID, aColor)
+{
+  // Only show editor colors from prefs if we're in custom mode
+  if (!document.getElementById("editor.use_custom_colors").value)
+    return;
+
+  SetColors(aColorWellID, aPreviewID, aColor)
+}
+
+function SetColors(aColorWellID, aPreviewID, aColor)
+{
+  SetColorWell(aColorWellID, aColor);
+  SetColorPreview(aPreviewID, aColor);
+}
+
+function SetColorWell(aColorWellID, aColor)
+{
+  document.getElementById(aColorWellID).style.backgroundColor = aColor;
+}
+
+function SetColorPreview(aPreviewID, aColor)
+{
+  if (aPreviewID == "ColorPreview")
+    document.getElementById(aPreviewID).style.backgroundColor = aColor;
+  else
+    document.getElementById(aPreviewID).style.color = aColor;
+}
+
+function UpdateBgImagePreview(aImage)
+{
+  var colorPreview = document.getElementById("ColorPreview");
+  colorPreview.style.backgroundImage = aImage && "url(" + aImage + ")";
+}
+
+// Sets browser background/foreground colors
+function SetBgAndFgColors(aSysPrefEnabled)
+{
+  if (aSysPrefEnabled)
+  { // Use system colors
+    SetColorPreview("normalText", "windowtext");
+    SetColorPreview("ColorPreview", "window");
+  }
+  else
+  {
+    SetColorPreview("normalText", gPrefService.getCharPref("browser.display.foreground_color"));
+    SetColorPreview("ColorPreview", gPrefService.getCharPref("browser.display.background_color"));
+  }
+}
+
+function ChooseImageFile()
+{
+  const nsIFilePicker = Components.interfaces.nsIFilePicker;
+  var fp = Components.classes["@mozilla.org/filepicker;1"]
+                     .createInstance(nsIFilePicker);
+  var editorBundle = document.getElementById("bundle_editor");
+  var title = editorBundle.getString("SelectImageFile");
+  fp.init(window, title, nsIFilePicker.modeOpen);
+  fp.appendFilters(nsIFilePicker.filterImages);
+  if (fp.show() == nsIFilePicker.returnOK)
+    document.getElementById("editor.default_background_image").value = fp.fileURL.spec;
+
+  var textbox = document.getElementById("backgroundImageInput");
+  textbox.focus();
+  textbox.select();
+}
+
+function WindowOnUnload()
+{
+  gPrefService.removeObserver("browser.display.use_system_colors", browserPrefsObserver, false);
+  gPrefService.removeObserver("browser.display.foreground_color", browserPrefsObserver, false);
+  gPrefService.removeObserver("browser.display.background_color", browserPrefsObserver, false);
+  gPrefService.removeObserver("browser.anchor_color", browserPrefsObserver, false);
+  gPrefService.removeObserver("browser.active_color", browserPrefsObserver, false);
+  gPrefService.removeObserver("browser.visited_color", browserPrefsObserver, false);
+  window.removeEventListener("unload", WindowOnUnload, false);
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/composer/content/pref-composer.xul
@@ -0,0 +1,127 @@
+<?xml version="1.0"?> 
+<!-- ***** BEGIN LICENSE BLOCK *****
+ Version: MPL 1.1/GPL 2.0/LGPL 2.1
+
+ The contents of this file are subject to the Mozilla Public License Version
+ 1.1 (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the
+ License.
+
+ The Original Code is Mozilla Communicator client code, released
+ March 31, 1998.
+
+ The Initial Developer of the Original Code is
+ Netscape Communications Corporation.
+ Portions created by the Initial Developer are Copyright (C) 1998-2000
+ the Initial Developer. All Rights Reserved.
+
+ Contributor(s):
+   Ryan Cassin (rcassin@supernova.org)
+
+ Alternatively, the contents of this file may be used under the terms of
+ either of the GNU General Public License Version 2 or later (the "GPL"),
+ or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ in which case the provisions of the GPL or the LGPL are applicable instead
+ of those above. If you wish to allow use of your version of this file only
+ under the terms of either the GPL or the LGPL, and not to allow others to
+ use your version of this file under the terms of the MPL, indicate your
+ decision by deleting the provisions above and replace them with the notice
+ and other provisions required by the GPL or the LGPL. If you do not delete
+ the provisions above, a recipient may use your version of this file under
+ the terms of any one of the MPL, the GPL or the LGPL.
+
+ ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://communicator/skin/" type="text/css"?>
+<?xul-overlay href="chrome://global/content/globalOverlay.xul"?>
+
+<!DOCTYPE overlay SYSTEM "chrome://editor/locale/pref-composer.dtd">
+
+<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <prefpane id="composer_pane" label="&pref.composer.title;">
+
+    <preferences id="composer_preferences">
+      <preference id="editor.history.url_maximum"
+                  name="editor.history.url_maximum"
+                  type="int"/>
+      <preference id="editor.prettyprint"
+                  name="editor.prettyprint"
+                  type="bool"
+                  inverted="true"/>
+      <preference id="editor.save_associated_files"
+                  name="editor.save_associated_files"
+                  type="bool"/>
+      <preference id="editor.always_show_publish_dialog"
+                  name="editor.always_show_publish_dialog"
+                  type="bool"/>
+      <preference id="editor.table.maintain_structure"
+                  name="editor.table.maintain_structure"
+                  type="bool"/>
+      <preference id="editor.use_css"
+                  name="editor.use_css"
+                  type="bool"/>
+      <preference id="editor.CR_creates_new_p"
+                  name="editor.CR_creates_new_p"
+                  type="bool"/>
+    </preferences>
+
+    <!-- Recent files menu -->
+    <groupbox>
+      <caption label="&recentFiles.title;"/>
+      <hbox align="center">
+        <label value="&documentsInMenu.label;"
+               accesskey="&documentsInMenu.accesskey;"
+               control="recentFiles"/>
+        <textbox id="recentFiles"
+                 name="recent string"
+                 type="number"
+                 max="99"
+                 min="0"
+                 maxlength="2"
+                 size="3"
+                 value="10"
+                 preference="editor.history.url_maximum"/>
+      </hbox>
+    </groupbox>
+
+    <!-- HTML formatting on output -->
+    <groupbox>
+      <caption label="&savingFiles.title;"/>
+      <checkbox id="preserveFormatting"
+                label="&preserveExisting.label;"
+                accesskey="&preserveExisting.accesskey;"
+                tooltiptext="&preserveExisting.tooltip;"
+                preference="editor.prettyprint"/>
+      <checkbox id="saveAssociatedFiles"
+                label="&saveAssociatedFiles.label;"
+                accesskey="&saveAssociatedFiles.accesskey;"
+                preference="editor.save_associated_files"/>
+      <checkbox id="showPublishDialog" 
+                label="&showPublishDialog.label;"
+                accesskey="&showPublishDialog.accesskey;"
+                preference="editor.always_show_publish_dialog"/>
+    </groupbox>
+
+    <groupbox align="start">
+      <caption label="&composerEditing.label;"/>
+      <checkbox id="maintainTableStructure"
+                label="&maintainStructure.label;"
+                accesskey="&maintainStructure.accesskey;"
+                tooltiptext="&maintainStructure.tooltip;"
+                preference="editor.table.maintain_structure"/>
+      <checkbox id="useCSS"
+                label="&useCSS.label;"
+                accesskey="&useCSS.accesskey;"
+                preference="editor.use_css"/>
+      <checkbox id="crInPCreatesNewP"
+                label="&crInPCreatesNewP.label;"
+                accesskey="&crInPCreatesNewP.accesskey;"
+                preference="editor.CR_creates_new_p"/>
+    </groupbox>
+  </prefpane>
+</overlay>
new file mode 100644
--- /dev/null
+++ b/editor/ui/composer/content/pref-editing.xul
@@ -0,0 +1,215 @@
+<?xml version="1.0"?> 
+<!-- ***** BEGIN LICENSE BLOCK *****
+ Version: MPL 1.1/GPL 2.0/LGPL 2.1
+
+ The contents of this file are subject to the Mozilla Public License Version
+ 1.1 (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the
+ License.
+
+ The Original Code is Mozilla Communicator client code, released
+ March 31, 1998.
+
+ The Initial Developer of the Original Code is
+ Netscape Communications Corporation.
+ Portions created by the Initial Developer are Copyright (C) 1998-2000
+ the Initial Developer. All Rights Reserved.
+
+ Contributor(s):
+
+ Alternatively, the contents of this file may be used under the terms of
+ either of the GNU General Public License Version 2 or later (the "GPL"),
+ or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ in which case the provisions of the GPL or the LGPL are applicable instead
+ of those above. If you wish to allow use of your version of this file only
+ under the terms of either the GPL or the LGPL, and not to allow others to
+ use your version of this file under the terms of the MPL, indicate your
+ decision by deleting the provisions above and replace them with the notice
+ and other provisions required by the GPL or the LGPL. If you do not delete
+ the provisions above, a recipient may use your version of this file under
+ the terms of any one of the MPL, the GPL or the LGPL.
+
+ ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://communicator/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!DOCTYPE overlay SYSTEM "chrome://editor/locale/pref-editing.dtd">
+
+<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <prefpane id="editing_pane"
+            label="&pref.editing.title;"
+            script="chrome://editor/content/pref-composer.js">
+
+    <preferences id="editing_preferences">
+      <preference id="editor.author"
+                  name="editor.author"
+                  type="string"/>
+      <preference id="editor.use_custom_colors"
+                  name="editor.use_custom_colors"
+                  type="bool"
+                  onchange="UpdateDependent(this.value);"/>
+      <preference id="editor.text_color"
+                  name="editor.text_color"
+                  type="string"
+                  onchange="UpdateColors('textCW', 'normalText', this.value);"/>
+      <preference id="editor.link_color"
+                  name="editor.link_color"
+                  type="string"
+                  onchange="UpdateColors('linkCW', 'linkText', this.value);"/>
+      <preference id="editor.active_link_color"
+                  name="editor.active_link_color"
+                  type="string"
+                  onchange="UpdateColors('activeCW', 'activeLinkText', this.value);"/>
+      <preference id="editor.followed_link_color"
+                  name="editor.followed_link_color"
+                  type="string"
+                  onchange="UpdateColors('visitedCW', 'visitedLinkText', this.value);"/>
+      <preference id="editor.background_color"
+                  name="editor.background_color"
+                  type="string"
+                  onchange="UpdateColors('backgroundCW', 'ColorPreview', this.value);"/>
+      <preference id="editor.default_background_image"
+                  name="editor.default_background_image"
+                  type="string"
+                  onchange="UpdateBgImagePreview(this.value);"/>
+    </preferences>
+
+    <stringbundle id="bundle_editor"
+                  src="chrome://editor/locale/editor.properties"/>
+
+    <vbox>
+      <label value="&authorName.label;" 
+             accesskey="&authorName.accesskey;"
+             control="editorAuthor">
+      </label>
+      <hbox>
+        <textbox id="editorAuthor"
+                 flex="1"
+                 preference="editor.author"/>
+        <spacer flex="1"/>
+      </hbox>
+    </vbox>
+    <spacer class="smallspacer"/>
+    <groupbox align="start">
+      <caption label="&pageColorHeader;"/> 
+      <radiogroup id="useCustomColors"
+                  preference="editor.use_custom_colors">
+        <radio id="defaultColorsRadio"
+               value="false" 
+               label="&defaultColorsRadio.label;" 
+               accesskey="&defaultColors.accesskey;"/>
+        <radio id="customColorsRadio" 
+               value="true"
+               label="&customColorsRadio.label;"
+               accesskey="&customColors.accesskey;"/>
+      </radiogroup>
+      <hbox class="indent">
+        <grid>
+          <columns><column/><column/></columns>
+          <rows id="color-rows">
+            <row align="center">
+              <label id="textLabel"
+                     value="&normalText.label;&colon.character;" 
+                     accesskey="&normalText.accesskey;"
+                     control="text"/>
+              <button id="text"
+                      class="color-button"
+                      oncommand="GetColorAndUpdatePref('Text', 'text');">
+                <spacer id="textCW" class="color-well"/>
+              </button>
+            </row>
+            <row align="center">
+              <label id="linkLabel"
+                     value="&linkText.label;&colon.character;" 
+                     accesskey="&linkText.accesskey;"
+                     control="link"/>
+              <button id="link"
+                      class="color-button"
+                      oncommand="GetColorAndUpdatePref('Link', 'link');">
+                <spacer id="linkCW" class="color-well"/>
+              </button>
+            </row>
+            <row align="center">
+              <label id="activeLinkLabel"
+                     value="&activeLinkText.label;&colon.character;" 
+                     accesskey="&activeLinkText.accesskey;"
+                     control="active_link"/>
+              <button id="active_link"
+                      class="color-button"
+                      oncommand="GetColorAndUpdatePref('ActiveLink', 'active_link');">
+                <spacer id="activeCW" class="color-well"/>
+              </button>
+            </row>
+            <row align="center">
+              <label id="visitedLinkLabel"
+                     value ="&visitedLinkText.label;&colon.character;" 
+                     accesskey="&visitedLinkText.accesskey;"
+                     control="followed_link"/>
+              <button id="followed_link"
+                      class="color-button"
+                      oncommand="GetColorAndUpdatePref('VisitedLink', 'followed_link');">
+                <spacer id="visitedCW" class="color-well"/>
+              </button>
+            </row>
+            <row align="center">
+              <label id="backgroundLabel"
+                     value="&background.label;"
+                     accesskey="&background.accesskey;"
+                     control="background"/>
+              <button id="background"
+                      class="color-button"
+                      oncommand="GetColorAndUpdatePref('Page', 'background');">
+                <spacer id="backgroundCW" class="color-well"/>
+              </button>
+            </row>
+          </rows>
+        </grid>
+        <vbox id="ColorPreview"
+              flex="1">
+          <spacer flex="1"/>
+          <label id="normalText"
+                 class="larger"
+                 value="&normalText.label;"/>
+          <spacer flex="1"/>
+          <label id="linkText"
+                 class="larger"
+                 value="&linkText.label;"/>
+          <spacer flex="1"/>
+          <label id="activeLinkText"
+                 class="larger"
+                 value="&activeLinkText.label;"/>
+          <spacer flex="1"/>
+          <label id="visitedLinkText"
+                 class="larger"
+                 value="&visitedLinkText.label;"/>
+          <spacer flex="1"/>
+        </vbox>
+        <spacer flex="1"/>
+      </hbox>
+      <spacer class="spacer"/>
+      <label id="backgroundImageLabel"
+             value="&backgroundImage.label;"
+             accesskey="&backgroundImage.accesskey;"
+             control="backgroundImageInput">
+      </label>
+      <hbox align="center">
+        <textbox id="backgroundImageInput"
+                 class="uri-element"
+                 preference="editor.default_background_image"
+                 style="min-width: 23em;"
+                 flex="1"/>
+        <button label="&chooseFile.label;"
+                accesskey="&chooseFile.accesskey;"
+                oncommand="ChooseImageFile();">
+          <observes element="backgroundImageInput" attribute="disabled"/>
+        </button>
+      </hbox>
+    </groupbox>
+  </prefpane>
+</overlay>
new file mode 100644
--- /dev/null
+++ b/editor/ui/composer/content/pref-toolbars.xul
@@ -0,0 +1,231 @@
+<?xml version="1.0"?>
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Editor Toolbar Preferences.
+   -
+   - The Initial Developer of the Original Code is
+   - Neil Rashbrook.
+   - Portions created by the Initial Developer are Copyright (C) 2003
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s): Neil Rashbrook <neil@parkwaycc.co.uk>
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either the GNU General Public License Version 2 or later (the "GPL"), or
+   - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the LGPL or the GPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+
+<!DOCTYPE overlay SYSTEM "chrome://editor/locale/pref-toolbars.dtd">
+
+<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <prefpane id="toolbars_pane"
+            label="&pref.toolbars.title;">
+
+    <preferences id="toolbars_preferences">
+      <preference id="editor.toolbars.showbutton.new"
+                  name="editor.toolbars.showbutton.new"
+                  type="bool"/>
+      <preference id="editor.toolbars.showbutton.open"
+                  name="editor.toolbars.showbutton.open"
+                  type="bool"/>
+      <preference id="editor.toolbars.showbutton.save"
+                  name="editor.toolbars.showbutton.save"
+                  type="bool"/>
+      <preference id="editor.toolbars.showbutton.publish"
+                  name="editor.toolbars.showbutton.publish"
+                  type="bool"/>
+      <preference id="editor.toolbars.showbutton.preview"
+                  name="editor.toolbars.showbutton.preview"
+                  type="bool"/>
+      <preference id="editor.toolbars.showbutton.cut"
+                  name="editor.toolbars.showbutton.cut"
+                  type="bool"/>
+      <preference id="editor.toolbars.showbutton.copy"
+                  name="editor.toolbars.showbutton.copy"
+                  type="bool"/>
+      <preference id="editor.toolbars.showbutton.paste"
+                  name="editor.toolbars.showbutton.paste"
+                  type="bool"/>
+      <preference id="editor.toolbars.showbutton.print"
+                  name="editor.toolbars.showbutton.print"
+                  type="bool"/>
+      <preference id="editor.toolbars.showbutton.find"
+                  name="editor.toolbars.showbutton.find"
+                  type="bool"/>
+      <preference id="editor.toolbars.showbutton.image"
+                  name="editor.toolbars.showbutton.image"
+                  type="bool"/>
+      <preference id="editor.toolbars.showbutton.hline"
+                  name="editor.toolbars.showbutton.hline"
+                  type="bool"/>
+      <preference id="editor.toolbars.showbutton.table"
+                  name="editor.toolbars.showbutton.table"
+                  type="bool"/>
+      <preference id="editor.toolbars.showbutton.link"
+                  name="editor.toolbars.showbutton.link"
+                  type="bool"/>
+      <preference id="editor.toolbars.showbutton.namedAnchor"
+                  name="editor.toolbars.showbutton.namedAnchor"
+                  type="bool"/>
+      <preference id="editor.toolbars.showbutton.DecreaseFontSize"
+                  name="editor.toolbars.showbutton.DecreaseFontSize"
+                  type="bool"/>
+      <preference id="editor.toolbars.showbutton.IncreaseFontSize"
+                  name="editor.toolbars.showbutton.IncreaseFontSize"
+                  type="bool"/>
+      <preference id="editor.toolbars.showbutton.bold"
+                  name="editor.toolbars.showbutton.bold"
+                  type="bool"/>
+      <preference id="editor.toolbars.showbutton.absolutePosition"
+                  name="editor.toolbars.showbutton.absolutePosition"
+                  type="bool"/>
+      <preference id="editor.toolbars.showbutton.ul"
+                  name="editor.toolbars.showbutton.ul"
+                  type="bool"/>
+      <preference id="editor.toolbars.showbutton.ol"
+                  name="editor.toolbars.showbutton.ol"
+                  type="bool"/>
+      <preference id="editor.toolbars.showbutton.italic"
+                  name="editor.toolbars.showbutton.italic"
+                  type="bool"/>
+      <preference id="editor.toolbars.showbutton.decreaseZIndex"
+                  name="editor.toolbars.showbutton.decreaseZIndex"
+                  type="bool"/>
+      <preference id="editor.toolbars.showbutton.outdent"
+                  name="editor.toolbars.showbutton.outdent"
+                  type="bool"/>
+      <preference id="editor.toolbars.showbutton.indent"
+                  name="editor.toolbars.showbutton.indent"
+                  type="bool"/>
+      <preference id="editor.toolbars.showbutton.underline"
+                  name="editor.toolbars.showbutton.underline"
+                  type="bool"/>
+      <preference id="editor.toolbars.showbutton.increaseZIndex"
+                  name="editor.toolbars.showbutton.increaseZIndex"
+                  type="bool"/>
+    </preferences>
+
+    <groupbox orient="horizontal">
+      <caption label="&composition.caption;"/>
+      <vbox flex="1">
+        <checkbox id="showNew"
+                  label="&new.label;"
+                  preference="editor.toolbars.showbutton.new"/>
+        <checkbox id="showOpen"
+                  label="&open.label;"
+                  preference="editor.toolbars.showbutton.open"/>
+        <checkbox id="showSave"
+                  label="&save.label;"
+                  preference="editor.toolbars.showbutton.save"/>
+        <checkbox id="showPublish"
+                  label="&publish.label;"
+                  preference="editor.toolbars.showbutton.publish"/>
+        <checkbox id="showPreview"
+                  label="&preview.label;"   
+                  preference="editor.toolbars.showbutton.preview"/>
+      </vbox>
+      <vbox flex="1">
+        <checkbox id="showCut"
+                  label="&cut.label;"
+                  preference="editor.toolbars.showbutton.cut"/>
+        <checkbox id="showCopy"
+                  label="&copy.label;"
+                  preference="editor.toolbars.showbutton.copy"/>
+        <checkbox id="showPaste"
+                  label="&paste.label;"
+                  preference="editor.toolbars.showbutton.paste"/>
+        <checkbox id="showPrint"
+                  label="&print.label;"
+                  preference="editor.toolbars.showbutton.print"/>
+        <checkbox id="showFind"
+                  label="&find.label;"
+                  preference="editor.toolbars.showbutton.find"/>
+      </vbox>
+      <vbox flex="1">
+        <checkbox id="showImage"
+                  label="&image.label;"
+                  preference="editor.toolbars.showbutton.image"/>
+        <checkbox id="showHline"
+                  label="&hline.label;"
+                  preference="editor.toolbars.showbutton.hline"/>
+        <checkbox id="showTable"
+                  label="&table.label;"
+                  preference="editor.toolbars.showbutton.table"/>
+        <checkbox id="showLink"
+                  label="&link.label;"
+                  preference="editor.toolbars.showbutton.link"/>
+        <checkbox id="showAnchor"
+                  label="&anchor.label;"
+                  preference="editor.toolbars.showbutton.namedAnchor"/>
+      </vbox>
+    </groupbox>
+
+    <groupbox orient="horizontal">
+      <caption label="&formatting.caption;"/>
+      <vbox flex="1">
+        <checkbox id="showSmaller"
+                  label="&smaller.label;"
+                  preference="editor.toolbars.showbutton.DecreaseFontSize"/>
+        <checkbox id="showLarger"
+                  label="&larger.label;"
+                  preference="editor.toolbars.showbutton.IncreaseFontSize"/>
+        <checkbox id="showBold"
+                  label="&bold.label;"
+                  preference="editor.toolbars.showbutton.bold"/>
+        <checkbox id="showAbsolutePosition"
+                  label="&absolutePosition.label;"
+                  preference="editor.toolbars.showbutton.absolutePosition"/>
+      </vbox>
+      <vbox flex="1">
+        <checkbox id="showBullets"
+                  label="&bullets.label;"
+                  preference="editor.toolbars.showbutton.ul"/>
+        <checkbox id="showNumbers"
+                  label="&numbers.label;"
+                  preference="editor.toolbars.showbutton.ol"/>
+        <checkbox id="showItalic"
+                  label="&italic.label;"
+                  preference="editor.toolbars.showbutton.italic"/>
+        <checkbox id="showDecreaseZIndex"
+                  label="&decreaseZIndex.label;"
+                  preference="editor.toolbars.showbutton.decreaseZIndex"/>
+      </vbox>
+      <vbox flex="1">
+        <checkbox id="showOutdent"
+                  label="&outdent.label;"
+                  preference="editor.toolbars.showbutton.outdent"/>
+        <checkbox id="showIndent"
+                  label="&indent.label;"
+                  preference="editor.toolbars.showbutton.indent"/>
+        <checkbox id="showUnderline"
+                  label="&underline.label;"
+                  preference="editor.toolbars.showbutton.underline"/>
+        <checkbox id="showIncreaseZIndex"
+                  label="&increaseZIndex.label;"
+                  preference="editor.toolbars.showbutton.increaseZIndex"/>
+      </vbox>
+    </groupbox>
+  </prefpane>
+</overlay>
new file mode 100644
--- /dev/null
+++ b/editor/ui/composer/content/publishprefs.js
@@ -0,0 +1,951 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   cmanske@netscape.com
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+
+/****************** Get publishing data methods *******************/
+
+// Build an array of all publish site data obtained from prefs
+function GetPublishSiteData()
+{
+  var publishBranch = GetPublishPrefsBranch();
+  if (!publishBranch)
+    return null;
+
+  // Array of site names - sorted, but don't put default name first
+  var siteNameList = GetSiteNameList(true, false);
+  if (!siteNameList)
+    return null;
+
+  // Array of all site data
+  var siteArray = [];
+
+  // We  rewrite siteName prefs to eliminate names if data is bad
+  //  and to be sure order is the same as sorted name list
+  try {
+    publishBranch.deleteBranch("site_name.");
+  } catch (e) {}
+
+  // Get publish data using siteName as the key
+  var index = 0;
+  for (var i = 0; i < siteNameList.length; i++)
+  {
+    // Associated data uses site name as key
+    var publishData = GetPublishData_internal(publishBranch, siteNameList[i]);
+    if (publishData)
+    {
+      siteArray[index] = publishData;
+      SetPublishStringPref(publishBranch, "site_name."+index, siteNameList[i]);
+      index++;
+    }
+    else
+    {
+      try {
+        // Remove bad site prefs now
+        publishBranch.deleteBranch("site_data." + siteNameList[i] + ".");
+      } catch (e) {}
+    }
+  }
+
+  SavePrefFile();
+
+  if (index == 0) // No Valid pref records found!
+    return null;
+
+
+  return siteArray;
+}
+
+function GetDefaultPublishSiteName()
+{
+  var publishBranch = GetPublishPrefsBranch();
+  var name = "";  
+  if (publishBranch)
+    name = GetPublishStringPref(publishBranch, "default_site");
+
+  return name;
+}
+
+// Return object with all info needed to publish
+//   from database of sites previously published to.
+function CreatePublishDataFromUrl(docUrl)
+{
+  if (!docUrl || IsUrlAboutBlank(docUrl) || GetScheme(docUrl) == "file")
+    return null;
+
+  var pubSiteData = GetPublishSiteData();
+  if (pubSiteData)
+  {
+    var dirObj = {};
+    var index = FindSiteIndexAndDocDir(pubSiteData, docUrl, dirObj);
+    var publishData;
+    if (index != -1)
+    {
+      publishData = pubSiteData[index];
+      publishData.docDir = FormatDirForPublishing(dirObj.value)
+
+      //XXX Problem: OtherDir: How do we decide when to use the dir in 
+      //    publishSiteData (default DocDir) or docDir from current filepath?
+      publishData.otherDir = FormatDirForPublishing(pubSiteData[index].otherDir);
+
+      publishData.filename = GetFilename(docUrl);
+      publishData.notInSiteData = false;
+      return publishData;
+    }
+  }
+
+  // Document wasn't found in publish site database
+  // Create data just from URL
+
+  // Extract username and password from docUrl
+  var userObj = {};
+  var passObj = {};
+  var pubUrl = StripUsernamePassword(docUrl, userObj, passObj);
+
+  // Strip off filename
+  var lastSlash = pubUrl.lastIndexOf("\/");
+  //XXX Look for "?", "=", and "&" ?
+  pubUrl = pubUrl.slice(0, lastSlash+1);
+
+  var siteName = CreateSiteNameFromUrl(pubUrl, pubSiteData);
+
+  publishData = { 
+    siteName : siteName,
+    previousSiteName : siteName,
+    filename : GetFilename(docUrl),
+    username : userObj.value,
+    password : passObj.value,
+    savePassword : false,
+    publishUrl : pubUrl,
+    browseUrl  : pubUrl,
+    docDir     : "",
+    otherDir   : "",
+    publishOtherFiles : true,
+    dirList    : [""],
+    saveDirs   : false,
+    notInSiteData : true
+  }
+
+  return publishData;
+}
+
+function CreateSiteNameFromUrl(url, publishSiteData)
+{
+  var host = GetHost(url);
+  var schemePostfix = " (" + GetScheme(url) + ")";
+  var siteName = host + schemePostfix;
+
+  if (publishSiteData)
+  {
+    // Look for duplicates. Append "-1"  etc until unique name found
+    var i = 1;
+    var exists = false;
+    do {
+      exists = PublishSiteNameExists(siteName, publishSiteData, -1)  
+      if (exists)
+        siteName = host + "-" + i + schemePostfix;
+      i++;
+    }
+    while (exists);
+  }
+  return siteName;
+}
+
+// Similar to above, but in param is a site profile name
+// Note that this is more efficient than getting from a URL,
+//   since we don't have to get all the sitedata but can key off of sitename.
+// Caller must supply the current docUrl or just a filename
+// If doc URL is supplied, we find the publish subdirectory if publishUrl is part of docUrl
+function GetPublishDataFromSiteName(siteName, docUrlOrFilename)
+{
+  var publishBranch = GetPublishPrefsBranch();
+  if (!publishBranch)
+    return null;
+
+  var siteNameList = GetSiteNameList(false, false);
+  if (!siteNameList)
+    return null;
+  for (var i = 0; i < siteNameList.length; i++)
+  {
+    if (siteNameList[i] == siteName)
+    {
+      var publishData = GetPublishData_internal(publishBranch, siteName);
+      if (GetScheme(docUrlOrFilename))
+        FillInMatchingPublishData(publishData, docUrlOrFilename);
+      else
+        publishData.filename = docUrlOrFilename;
+
+      return publishData;
+    }
+  }
+  return null;
+}
+
+function GetDefaultPublishData()
+{
+  var publishBranch = GetPublishPrefsBranch();
+  if (!publishBranch)
+    return null;
+
+  var siteName = GetPublishStringPref(publishBranch, "default_site");
+  if (!siteName)
+    return null;
+
+  return GetPublishData_internal(publishBranch, siteName);
+}
+
+function GetPublishData_internal(publishBranch, siteName)
+{
+  if (!publishBranch || !siteName)
+    return null;
+
+  var prefPrefix = "site_data." + siteName + ".";
+
+  // We must have a publish url, else we ignore this site
+  // (siteData and siteNames for sites with incomplete data 
+  //  will get deleted by SavePublishSiteDataToPrefs)
+  var publishUrl = GetPublishStringPref(publishBranch, prefPrefix+"url");
+  if (!publishUrl)
+    return null;
+
+  var savePassword = false;
+  var publishOtherFiles = true;
+  try {
+    savePassword = publishBranch.getBoolPref(prefPrefix+"save_password");
+    publishOtherFiles = publishBranch.getBoolPref(prefPrefix+"publish_other_files");
+  } catch (e) {}
+
+  var publishData = { 
+    siteName : siteName,
+    previousSiteName : siteName,
+    filename : "",
+    username : GetPublishStringPref(publishBranch, prefPrefix+"username"),
+    savePassword : savePassword,
+    publishUrl : publishUrl,
+    browseUrl  : GetPublishStringPref(publishBranch, prefPrefix+"browse_url"),
+    docDir     : FormatDirForPublishing(GetPublishStringPref(publishBranch, prefPrefix+"doc_dir")),
+    otherDir   : FormatDirForPublishing(GetPublishStringPref(publishBranch, prefPrefix+"other_dir")),
+    publishOtherFiles : publishOtherFiles,
+    saveDirs : false
+  }
+
+  // Get password from PasswordManager
+  publishData.password = GetSavedPassword(publishData);
+
+  // If password was found, user must have checked "Save password"
+  //    checkbox in prompt outside of publishing, so override the pref we stored
+  if (publishData.password)
+  {
+    if (!savePassword)
+    {
+      try {
+        publishPrefsBranch.setBoolPref(prefPrefix+"save_password", true);
+      } catch (e) {}
+    }
+    publishData.savePassword = true;
+  }
+
+  // Build history list of directories 
+  // Always supply the root dir 
+  publishData.dirList = [""];
+
+  // Get the rest from prefs
+  var dirCount = {value:0};
+  var dirPrefs;
+  try {
+    dirPrefs = publishBranch.getChildList(prefPrefix+"dir.", dirCount);
+  } catch (e) {}
+
+  if (dirPrefs && dirCount.value > 0)
+  {
+    if (dirCount.value > 1)
+      dirPrefs.sort();
+
+    for (var j = 0; j < dirCount.value; j++)
+    {
+      var dirName = GetPublishStringPref(publishBranch, dirPrefs[j]);
+      if (dirName)
+        publishData.dirList[j+1] = dirName;
+    }
+  }
+
+  return publishData;
+}
+
+/****************** Save publishing data methods *********************/
+
+// Save the siteArray containing all current publish site data
+function SavePublishSiteDataToPrefs(siteArray, defaultName)
+{
+  var publishBranch = GetPublishPrefsBranch();
+  if (!publishBranch)
+    return false;
+
+  try {
+    if (siteArray)
+    {
+      var defaultFound = false;
+
+      // Clear existing names and data -- rebuild all site prefs
+      publishBranch.deleteBranch("site_name.");
+      publishBranch.deleteBranch("site_data.");
+
+      for (var i = 0; i < siteArray.length; i++)
+      {
+        SavePublishData_Internal(publishBranch, siteArray[i], i);
+        if (!defaultFound)
+          defaultFound = defaultName == siteArray[i].siteName;
+      }
+      // Assure that we have a default name
+      if (siteArray.length && !defaultFound)
+        defaultName = siteArray[0].siteName;
+    }
+
+    // Save default site name
+    SetPublishStringPref(publishBranch, "default_site", defaultName);
+  
+    // Force saving to file so next page edited finds these values
+    SavePrefFile();
+  }
+  catch (ex) { return false; }
+
+  return true;
+}
+
+// Update prefs if publish site already exists
+//  or add prefs for a new site
+function SavePublishDataToPrefs(publishData)
+{
+  if (!publishData || !publishData.publishUrl)
+    return false;
+
+  var publishBranch = GetPublishPrefsBranch();
+  if (!publishBranch)
+    return false;
+
+  // Create name from URL if no site name is provided
+  if (!publishData.siteName)
+    publishData.siteName = CreateSiteNameFromUrl(publishData.publishUrl, publishData);
+
+  var siteCount = {value:0};
+  var siteNamePrefs;
+  try {
+    siteNamePrefs = publishBranch.getChildList("site_name.", siteCount);
+  } catch (e) {}
+
+  if (!siteNamePrefs || siteCount.value == 0)
+  {
+    // We currently have no site prefs, so create them
+    var siteData = [publishData];
+    return SavePublishSiteDataToPrefs(siteData, publishData.siteName);
+  }
+
+  // Use "previous" name if available in case it was changed
+  var previousSiteName =  ("previousSiteName" in publishData && publishData.previousSiteName) ? 
+                            publishData.previousSiteName : publishData.siteName;
+
+  // Find site number of existing site or fall through at next available one
+  // (Number is arbitrary; needed to construct unique "site_name.x" pref string)
+  for (var i = 0; i < siteCount.value; i++)
+  {
+    var siteName = GetPublishStringPref(publishBranch, "site_name."+i);
+
+    if (siteName == previousSiteName)
+    {
+      // Delete prefs for an existing site
+      try {
+        publishBranch.deleteBranch("site_data." + siteName + ".");
+      } catch (e) {}
+      break;
+    }
+  }
+
+  // We've taken care of finding old duplicate, so be sure 'previous name' is current
+  publishData.previousSiteName = publishData.siteName;
+
+  var ret = SavePublishData_Internal(publishBranch, publishData, i);
+  if (ret)
+  {
+    // Check if siteName was the default and we need to update that
+    var defaultSiteName = GetPublishStringPref(publishBranch, "default_site");
+    if (previousSiteName == defaultSiteName 
+        && publishData.siteName != defaultSiteName)
+      SetPublishStringPref(publishBranch, "default_site", publishData.siteName);
+
+    SavePrefFile();
+
+    // Clear signal to save these data
+    if ("notInSiteData" in publishData && publishData.notInSiteData)
+      publishData.notInSiteData = false;
+  }
+  return ret;
+}
+
+// Save data at a particular site number
+function SavePublishData_Internal(publishPrefsBranch, publishData, siteIndex)
+{
+  if (!publishPrefsBranch || !publishData)
+    return false;
+
+  SetPublishStringPref(publishPrefsBranch, "site_name."+siteIndex, publishData.siteName);
+
+  FixupUsernamePasswordInPublishData(publishData);
+
+  var prefPrefix = "site_data." + publishData.siteName + "."
+
+  SetPublishStringPref(publishPrefsBranch, prefPrefix+"url", publishData.publishUrl);
+  SetPublishStringPref(publishPrefsBranch, prefPrefix+"browse_url", publishData.browseUrl);
+  SetPublishStringPref(publishPrefsBranch, prefPrefix+"username", publishData.username);
+  
+  try {
+    publishPrefsBranch.setBoolPref(prefPrefix+"save_password", publishData.savePassword);
+    publishPrefsBranch.setBoolPref(prefPrefix+"publish_other_files", publishData.publishOtherFiles);
+  } catch (e) {}
+
+  // Save password using PasswordManager 
+  // (If publishData.savePassword = false, this clears existing password)
+  SavePassword(publishData);
+
+  SetPublishStringPref(publishPrefsBranch, prefPrefix+"doc_dir", 
+                       FormatDirForPublishing(publishData.docDir));
+
+  if (publishData.publishOtherFiles && publishData.otherDir)
+    SetPublishStringPref(publishPrefsBranch, prefPrefix+"other_dir",
+                         FormatDirForPublishing(publishData.otherDir));
+
+  if ("saveDirs" in publishData && publishData.saveDirs)
+  {
+    if (publishData.docDir)
+      AppendNewDirToList(publishData, publishData.docDir);
+
+    if (publishData.publishOtherFiles && publishData.otherDir 
+        && publishData.otherDir != publishData.docDir)
+      AppendNewDirToList(publishData, publishData.otherDir);
+  }
+
+  // Save array of subdirectories with site
+  if (publishData.dirList.length)
+  {
+    publishData.dirList.sort();
+    var dirIndex = 0;
+    for (var j = 0; j < publishData.dirList.length; j++)
+    {
+      var dir = publishData.dirList[j];
+
+      // Don't store the root dir
+      if (dir && dir != "/")
+      {
+        SetPublishStringPref(publishPrefsBranch, prefPrefix + "dir." + dirIndex, dir);
+        dirIndex++;
+      }
+    }
+  }
+
+  return true;
+}
+
+function AppendNewDirToList(publishData, newDir)
+{
+  newDir = FormatDirForPublishing(newDir);
+  if (!publishData || !newDir)
+    return;
+
+  if (!publishData.dirList)
+  {
+    publishData.dirList = [newDir];
+    return;
+  }
+
+  // Check if already in the list
+  for (var i = 0; i < publishData.dirList.length; i++)
+  {
+    // Don't add if already in the list
+    if (newDir == publishData.dirList[i])
+      return;
+  }
+  // Add to end of list
+  publishData.dirList[publishData.dirList.length] = newDir;
+}
+
+function RemovePublishSubdirectoryFromPrefs(publishData, removeDir)
+{
+  removeDir = FormatDirForPublishing(removeDir);
+  if (!publishData || !publishData.siteName || !removeDir)
+    return false;
+
+  var publishBranch = GetPublishPrefsBranch();
+  if (!publishBranch)
+    return false;
+
+  var prefPrefix = "site_data." + publishData.siteName + ".";
+
+  // Remove dir from the default dir prefs
+  if (publishData.docDir == removeDir)
+  {
+    publishData.docDir = "";
+    SetPublishStringPref(publishBranch, prefPrefix+"doc_dir", "");
+  }
+
+  if (publishData.otherDir == removeDir)
+  {
+    publishData.otherDir = "";
+    SetPublishStringPref(publishBranch, prefPrefix+"other_dir", "");
+  }
+
+  prefPrefix += "dir.";
+
+  // Delete entire subdir list
+  try {
+    publishBranch.deleteBranch(prefPrefix);
+  } catch (e) {}
+
+  // Rebuild prefs, skipping over site to remove
+  if (publishData.dirList.length)
+  {
+    var dirIndex = 0;
+    var docDirInList = false;
+    var otherDirInList = false;
+    for (var i = 0; i < publishData.dirList.length; i++)
+    {
+      var dir = publishData.dirList[i];
+      if (dir == removeDir)
+      {
+        // Remove item from the dirList array
+        publishData.dirList.splice(i, 1);
+        --i;
+      }
+      else if (dir && dir != "/") // skip empty or root dir
+      {
+        // Save to prefs
+        SetPublishStringPref(publishBranch, prefPrefix + dirIndex, dir);
+        dirIndex++;
+      }
+    }
+  }
+  SavePrefFile();
+  return true;
+}
+
+function SetDefaultSiteName(name)
+{
+  if (name)
+  {
+    var publishBranch = GetPublishPrefsBranch();
+    if (publishBranch)
+      SetPublishStringPref(publishBranch, "default_site", name);
+
+    SavePrefFile();
+  }
+}
+
+function SavePrefFile()
+{
+  try {
+    if (gPrefsService)
+      gPrefsService.savePrefFile(null);
+  }
+  catch (e) {}
+}
+
+/***************** Helper / utility methods ********************/
+
+function GetPublishPrefsBranch()
+{
+  var prefsService = GetPrefsService();
+  if (!prefsService)
+    return null;
+
+  return prefsService.getBranch("editor.publish.");
+}
+
+function GetSiteNameList(doSort, defaultFirst)
+{
+  var publishBranch = GetPublishPrefsBranch();
+  if (!publishBranch)
+    return null;
+
+  var siteCountObj = {value:0};
+  var siteNamePrefs;
+  try {
+    siteNamePrefs = publishBranch.getChildList("site_name.", siteCountObj);
+  } catch (e) {}
+
+  if (!siteNamePrefs || siteCountObj.value == 0)
+    return null;
+
+  // Array of site names
+  var siteNameList = [];
+  var index = 0;
+  var defaultName = "";
+  if (defaultFirst)
+  {
+    defaultName = GetPublishStringPref(publishBranch, "default_site");
+    // This always sorts to top -- replace with real string below
+    siteNameList[0] = "";
+    index++;
+  }
+
+  for (var i = 0; i < siteCountObj.value; i++)
+  {
+    var siteName = GetPublishStringPref(publishBranch, siteNamePrefs[i]);
+    // Skip if siteName pref is empty or is default name
+    if (siteName && siteName != defaultName)
+    {
+      siteNameList[index] = siteName;
+      index++;
+    }
+  }
+
+  if (siteNameList.length && doSort)
+    siteNameList.sort();
+
+  if (defaultName)
+  {
+    siteNameList[0] = defaultName;
+    index++;
+  }
+
+  return siteNameList.length? siteNameList : null;
+}
+
+function PublishSiteNameExists(name, publishSiteData, skipSiteIndex)
+{
+  if (!name)
+    return false;
+
+  if (!publishSiteData)
+  {
+    publishSiteData = GetPublishSiteData();
+    skipSiteIndex = -1;
+  }
+
+  if (!publishSiteData)
+    return false;
+
+  // Array of site names - sorted, but don't put default name first
+  for (var i = 0; i < publishSiteData.length; i++)
+  {
+    if (i != skipSiteIndex && name == publishSiteData[i].siteName)
+      return true;
+  }
+  return false;
+}
+
+// Find index of a site record in supplied publish site database
+// docUrl: Document URL with or without filename
+//         (Must end in "/" if no filename)
+// dirObj.value =  the directory of the document URL 
+//      relative to the base publishing URL, using "" if none
+//
+// XXX: Currently finds the site with the longest-matching url;
+//      should we look for the shortest instead? Or match just the host portion?
+function FindSiteIndexAndDocDir(publishSiteData, docUrl, dirObj)
+{
+  if (dirObj)
+    dirObj.value = "";
+
+  if (!publishSiteData || !docUrl || GetScheme(docUrl) == "file")
+    return -1;
+
+  var siteIndex = -1;
+  var siteUrlLen = 0;
+  
+  for (var i = 0; i < publishSiteData.length; i++)
+  {
+    // Site publish or browse url needs to be contained in document URL,
+    //  but that may also have a directory after the site base URL
+    //  So we must examine all records to find the site URL that best
+    //    matches the document URL: the longest-matching substring (XXX is this right?)
+    var lenObj = {value:0};
+    var tempData = Clone(publishSiteData[i]);
+
+    // Check if this site matches docUrl (returns length of match if found)
+    var len = FillInMatchingPublishData(tempData, docUrl);
+
+    if (len > siteUrlLen)
+    {
+      siteIndex = i;
+      siteUrlLen = len;
+      if (dirObj)
+        dirObj.value = tempData.docDir;
+
+      // Continue to find the site with longest-matching publishUrl
+    }
+  }
+  return siteIndex;
+}
+
+// Look for a matching publish url within the document url
+// (We need to look at both "publishUrl" and "browseUrl" in case we are editing
+//  an http: document but using ftp: to publish.)
+// If match is found:
+//    Fill in the filename and subirectory based on the docUrl and 
+//    return the length of the docUrl with username+password stripped out
+function FillInMatchingPublishData(publishData, docUrl)
+{
+  if (!publishData || !docUrl)
+    return 0;
+
+  // Separate docUrl into the base url and filename
+  var lastSlash = docUrl.lastIndexOf("\/");
+  var baseUrl = docUrl.slice(0, lastSlash+1);
+  var filename = docUrl.slice(lastSlash+1);
+    
+  // Strip username+password from docUrl because these
+  //  are stored separately in publishData, never embedded in the publishUrl
+  // If both docUrl and publishData contain usernames,
+  //   we must match that as well as the url
+  var username = {value:""};
+  baseUrl = StripUsernamePassword(baseUrl, username); 
+  username = username.value;
+
+  var matchedLength = 0;
+  var pubUrlFound = publishData.publishUrl ?
+                      baseUrl.indexOf(publishData.publishUrl) == 0 : false;
+  var browseUrlFound = publishData.browseUrl ?
+                          baseUrl.indexOf(publishData.browseUrl) == 0 : false;
+
+  if ((pubUrlFound || browseUrlFound) 
+      && (!username || !publishData.username || username == publishData.username))
+  {
+    // We found a match
+    matchedLength = pubUrlFound ? publishData.publishUrl.length 
+                            : publishData.browseUrl.length;
+
+    if (matchedLength > 0)
+    {
+      publishData.filename = filename;
+
+      // Subdirectory within the site is what's left in baseUrl after the matched portion
+      publishData.docDir = FormatDirForPublishing(baseUrl.slice(matchedLength));
+    }
+  }
+  return matchedLength;
+}
+
+// Prefs that don't exist will through an exception,
+//  so just return an empty string
+function GetPublishStringPref(prefBranch, name)
+{
+  if (prefBranch && name)
+  {
+    try {
+      return prefBranch.getComplexValue(name, Components.interfaces.nsISupportsString).data;
+    } catch (e) {}
+  }
+  return "";
+}
+
+function SetPublishStringPref(prefBranch, name, value)
+{
+  if (prefBranch && name)
+  {
+    try {
+        var str = Components.classes["@mozilla.org/supports-string;1"]
+                            .createInstance(Components.interfaces.nsISupportsString);
+        str.data = value;
+        prefBranch.setComplexValue(name, Components.interfaces.nsISupportsString, str);
+    } catch (e) {}
+  }
+}
+
+// Assure that a publishing URL ends in "/", "=", "&" or "?"
+// Username and password should always be extracted as separate fields
+//  and are not allowed to remain embedded in publishing URL
+function FormatUrlForPublishing(url)
+{
+  url = TrimString(StripUsernamePassword(url));
+  if (url)
+  {
+    var lastChar = url.charAt(url.length-1);
+    if (lastChar != "/" && lastChar != "=" && lastChar != "&" && lastChar  != "?")
+      return (url + "/");
+  }
+  return url;
+}
+
+// Username and password present in publish url are
+//  extracted into the separate "username" and "password" fields 
+//  of the publishData object
+// Returns true if we did change the publishData
+function FixupUsernamePasswordInPublishData(publishData)
+{
+  var ret = false;
+  if (publishData && publishData.publishUrl)
+  {
+    var userObj = {value:""};
+    var passObj = {value:""};
+    publishData.publishUrl = FormatUrlForPublishing(StripUsernamePassword(publishData.publishUrl, userObj, passObj));
+    if (userObj.value)
+    {
+      publishData.username = userObj.value;
+      ret = true;
+    }
+    if (passObj.value)
+    {
+      publishData.password = passObj.value;
+      ret = true;
+    }
+    // While we're at it, be sure browse URL is proper format
+    publishData.browseUrl = FormatUrlForPublishing(publishData.browseUrl);
+  }
+  return ret;
+}
+
+// Assure that a publishing directory ends with "/" and does not begin with "/"
+// Input dir is assumed to be a subdirectory string, not a full URL or pathname
+function FormatDirForPublishing(dir)
+{
+  dir = TrimString(dir);
+
+  // The "//" case is an expected "typo" filter
+  //  that simplifies code below!
+  if (!dir || dir == "/" || dir == "//")
+    return "";
+
+  // Remove leading "/"
+  if (dir.charAt(0) == "/")
+    dir = dir.slice(1);
+
+  // Append "/" at the end if necessary
+  var dirLen = dir.length;
+  var lastChar = dir.charAt(dirLen-1);
+  if (dirLen > 1 && lastChar != "/" && lastChar != "=" && lastChar != "&" && lastChar  != "?")
+    return (dir + "/");
+
+  return dir;
+}
+
+
+var gPasswordManager;
+function GetPasswordManager()
+{
+  if (!gPasswordManager)
+  {
+    var passwordManager = Components.classes["@mozilla.org/passwordmanager;1"].createInstance();
+    if (passwordManager)
+      gPasswordManager = passwordManager.QueryInterface(Components.interfaces.nsIPasswordManager);
+  }
+  return gPasswordManager;
+}
+
+var gPasswordManagerInternal;
+function GetPasswordManagerInternal()
+{
+  if (!gPasswordManagerInternal)
+  {
+    try {
+      gPasswordManagerInternal =
+        Components.classes["@mozilla.org/passwordmanager;1"].createInstance(
+          Components.interfaces.nsIPasswordManagerInternal);
+    } catch (e) {
+    }
+  }
+  return gPasswordManagerInternal;
+}
+
+function GetSavedPassword(publishData)
+{
+  if (!publishData)
+    return "";
+  var passwordManagerInternal = GetPasswordManagerInternal();
+  if (!passwordManagerInternal)
+    return "";
+
+  var host = {value:""};
+  var user =  {value:""};
+  var password = {value:""}; 
+  var url = GetUrlForPasswordManager(publishData);
+  
+  try {
+    passwordManagerInternal.findPasswordEntry
+      (url, publishData.username, "", host, user, password);
+    return password.value;
+  } catch (e) {}
+
+  return "";
+}
+
+function SavePassword(publishData)
+{
+  if (!publishData || !publishData.publishUrl || !publishData.username)
+    return false;
+
+  var passwordManager = GetPasswordManager();
+  if (passwordManager)
+  {
+    var url = GetUrlForPasswordManager(publishData);
+
+    // Remove existing entry
+    // (Note: there is no method to update a password for an existing entry)
+    try {
+      passwordManager.removeUser(url, publishData.username);
+    } catch (e) {}
+
+    // If SavePassword is true, add new password
+    if (publishData.savePassword)
+    {
+      try {
+        passwordManager.addUser(url, publishData.username, publishData.password);
+      } catch (e) {}
+    }
+    return true;
+  }
+  return false;
+}
+
+function GetUrlForPasswordManager(publishData)
+{
+  if (!publishData || !publishData.publishUrl)
+    return false;
+
+  var url;
+
+  // For FTP, we must embed the username into the url for a site address
+  // XXX Maybe we should we do this for HTTP as well???
+  if (publishData.username && GetScheme(publishData.publishUrl) == "ftp")
+    url = InsertUsernameIntoUrl(publishData.publishUrl, publishData.username);
+  else
+    url = publishData.publishUrl;
+
+  // Strip off terminal "/"
+  var len = url.length;
+  if (len && url.charAt(len-1) == "\/")
+    url = url.slice(0, len-1);
+  
+  return url;
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdAEAttributes.js
@@ -0,0 +1,1845 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Beth Epperson
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// HTML Attributes object for "Name" menulist
+var gHTMLAttr = {};
+
+// JS Events Attributes object for "Name" menulist
+var gJSAttr = {};
+
+
+// Core HTML attribute values //
+// This is appended to Name menulist when "_core" is attribute name
+var gCoreHTMLAttr =
+[
+  "^id",
+	"class",
+	"title"
+];
+
+// Core event attribute values //
+// This is appended to all JS menulists
+//   except those elements having "noJSEvents"
+//   as a value in their gJSAttr array.
+var gCoreJSEvents =
+[
+	"onclick",
+	"ondblclick",
+	"onmousedown",
+	"onmouseup",
+	"onmouseover",
+	"onmousemove",
+	"onmouseout",
+  "-",
+  "onkeypress",
+	"onkeydown",
+	"onkeyup"
+];
+
+// Following are commonly-used strings
+
+// Alse accept: sRGB: #RRGGBB //
+var gHTMLColors =
+[
+	"Aqua",
+	"Black",
+	"Blue",
+	"Fuchsia",
+	"Gray",
+	"Green",
+	"Lime",
+	"Maroon",
+	"Navy",
+	"Olive",
+	"Purple",
+	"Red",
+	"Silver",
+	"Teal",
+	"White",
+	"Yellow"
+];
+
+var gHAlign =
+[
+	"left",
+	"center",
+	"right"
+];
+
+var gHAlignJustify =
+[
+	"left",
+	"center",
+	"right",
+	"justify"
+];
+
+var gHAlignTableContent =
+[
+	"left",
+	"center",
+	"right",
+	"justify",
+	"char"
+];
+
+var gVAlignTable =
+[
+	"top",
+	"middle",
+	"bottom",
+	"baseline"
+];
+
+var gTarget =
+[
+  "_blank",
+  "_self",
+  "_parent",
+  "_top"
+];
+
+// ================ HTML Attributes ================ //
+/* For each element, there is an array of attributes,
+   whose name is the element name,
+   used to fill the "Attribute Name" menulist.
+   For each of those attributes, if they have a specific
+   set of values, those are listed in an array named:
+   "elementName_attName".
+
+   In each values string, the following characters
+   are signal to do input filtering:
+    "#"  Allow only integer values
+    "%"  Allow integer values or a number ending in "%"
+    "+"  Allow integer values and allow "+" or "-" as first character
+    "!"  Allow only one character
+    "^"  The first character can be only be A-Z, a-z, hyphen, underscore, colon or period
+    "$"  is an attribute required by HTML DTD
+*/
+
+/*
+   Most elements have the "dir" attribute,
+   so we use this value array
+   for all elements instead of specifying  
+   separately for each element
+*/
+gHTMLAttr.all_dir =
+[
+  "ltr",
+  "rtl"
+];
+
+
+gHTMLAttr.a =
+[
+  "charset",
+  "type",
+  "name",
+  "href",
+  "^hreflang",
+  "target",
+  "rel",
+  "rev",
+  "!accesskey",
+  "shape",		// with imagemap //
+  "coords",		// with imagemap //
+  "#tabindex",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.a_target = gTarget;
+
+gHTMLAttr.a_rel =
+[
+  "alternate",
+  "stylesheet",
+  "start",
+  "next",
+  "prev",
+  "contents",
+  "index",
+  "glossary",
+  "copyright",
+  "chapter",
+  "section",
+  "subsection",
+  "appendix",
+  "help",
+  "bookmark"
+];
+
+gHTMLAttr.a_rev =
+[
+  "alternate",
+  "stylesheet",
+  "start",
+  "next",
+  "prev",
+  "contents",
+  "index",
+  "glossary",
+  "copyright",
+  "chapter",
+  "section",
+  "subsection",
+  "appendix",
+  "help",
+  "bookmark"
+];
+
+gHTMLAttr.a_shape =
+[
+  "rect",
+  "circle",
+  "poly",
+  "default"
+];
+
+gHTMLAttr.abbr =
+[
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.acronym =
+[
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.address =
+[
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+// this is deprecated //
+gHTMLAttr.applet =
+[
+  "codebase",
+  "archive",
+  "code",
+  "object",
+  "alt",
+  "name",
+  "%$width",
+  "%$height",
+  "align",
+  "#hspace",
+  "#vspace",
+  "-",
+  "_core"
+];
+
+gHTMLAttr.applet_align =
+[
+  "top",
+  "middle",
+  "bottom",
+  "left",
+  "right"
+];
+
+gHTMLAttr.area =
+[
+  "shape",
+  "coords",
+  "href",
+  "nohref",
+  "target",
+  "$alt",
+  "#tabindex",
+  "!accesskey",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.area_target = gTarget;
+
+gHTMLAttr.area_shape =
+[
+  "rect",
+  "circle",
+  "poly",
+  "default"
+];
+
+gHTMLAttr.area_nohref =
+[
+  "nohref"
+];
+
+gHTMLAttr.b =
+[
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.base =
+[
+  "href",
+  "target"
+];
+
+gHTMLAttr.base_target = gTarget;
+
+// this is deprecated //
+gHTMLAttr.basefont =
+[
+  "^id",
+  "$size",
+  "color",
+  "face"
+];
+ 
+gHTMLAttr.basefont_color = gHTMLColors;
+
+gHTMLAttr.bdo =
+[
+  "_core",
+  "-",
+  "^lang",
+  "$dir"
+];
+
+gHTMLAttr.bdo_dir =
+[
+  "ltr",
+  "rtl"
+];
+
+gHTMLAttr.big =
+[
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+ 
+gHTMLAttr.blockquote =
+[
+  "cite",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.body =
+[
+  "background",
+  "bgcolor",
+  "text",
+  "link",
+  "vlink",
+  "alink",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.body_bgcolor = gHTMLColors;
+
+gHTMLAttr.body_text = gHTMLColors;
+
+gHTMLAttr.body_link = gHTMLColors;
+
+gHTMLAttr.body_vlink = gHTMLColors;
+
+gHTMLAttr.body_alink = gHTMLColors;
+
+gHTMLAttr.br =
+[
+  "clear",
+  "-",
+  "_core"
+];
+
+gHTMLAttr.br_clear =
+[
+  "none",
+  "left",
+  "all",
+  "right"
+];
+
+gHTMLAttr.button =
+[
+  "name",
+  "value",
+  "$type",
+  "disabled",
+  "#tabindex",
+  "!accesskey",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.button_type =
+[
+  "submit",
+  "button",
+  "reset"
+];
+
+gHTMLAttr.button_disabled =
+[
+  "disabled"
+];
+
+gHTMLAttr.caption =
+[
+  "align",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.caption_align =
+[
+  "top",
+  "bottom",
+  "left",
+  "right"
+];
+
+
+// this is deprecated //
+gHTMLAttr.center =
+[
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.cite =
+[
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.code =
+[
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.col =
+[
+  "#$span",
+  "%width",
+  "align",
+  "!char",
+  "#charoff",
+  "valign",
+  "char",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.col_span =
+[
+  "1"  // default
+];
+
+gHTMLAttr.col_align = gHAlignTableContent;
+
+gHTMLAttr.col_valign =
+[
+  "top",
+  "middle",
+  "bottom",
+  "baseline"
+];
+
+
+gHTMLAttr.colgroup =
+[
+  "#$span",
+  "%width",
+  "align",
+  "!char",
+  "#charoff",
+  "valign",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.colgroup_span =
+[
+  "1" // default
+];
+
+gHTMLAttr.colgroup_align = gHAlignTableContent;
+
+gHTMLAttr.colgroup_valign =
+[
+  "top",
+  "middle",
+  "bottom",
+  "baseline"
+];
+
+gHTMLAttr.dd =
+[
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.del =
+[
+  "cite",
+  "datetime",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.dfn =
+[
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+// this is deprecated //
+gHTMLAttr.dir =
+[
+  "compact",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.dir_compact =
+[
+  "compact"
+];
+
+gHTMLAttr.div =
+[
+  "align",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.div_align = gHAlignJustify;
+
+gHTMLAttr.dl =
+[
+  "compact",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.dl_compact =
+[
+  "compact"
+];
+
+
+gHTMLAttr.dt =
+[
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.em =
+[
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.fieldset =
+[
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+// this is deprecated //
+gHTMLAttr.font =
+[
+  "+size",
+  "color",
+  "face",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.font_color = gHTMLColors;
+
+gHTMLAttr.form =
+[
+  "$action",
+  "$method",
+  "enctype",
+  "accept",
+  "name",
+  "accept-charset",
+  "target",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.form_method =
+[
+  "get",
+  "post"
+];
+
+gHTMLAttr.form_enctype =
+[
+  "application/x-www-form-urlencoded"
+];
+
+gHTMLAttr.form_target = gTarget;
+
+gHTMLAttr.frame =
+[
+  "longdesc",
+  "name",
+  "src",
+  "#frameborder",
+  "#marginwidth",
+  "#marginheight",
+  "noresize",
+  "$scrolling"
+];
+
+gHTMLAttr.frame_frameborder =
+[
+  "1",
+  "0"
+];
+
+gHTMLAttr.frame_noresize =
+[
+  "noresize"
+];
+
+gHTMLAttr.frame_scrolling =
+[
+  "auto",
+  "yes",
+  "no"
+];
+
+
+gHTMLAttr.frameset =
+[
+  "rows",
+  "cols",
+  "-",
+  "_core"
+];
+
+gHTMLAttr.h1 =
+[
+  "align",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.h1_align = gHAlignJustify;
+
+gHTMLAttr.h2 =
+[
+  "align",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.h2_align = gHAlignJustify;
+
+gHTMLAttr.h3 =
+[
+  "align",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.h3_align =  gHAlignJustify;
+
+gHTMLAttr.h4 =
+[
+  "align",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.h4_align = gHAlignJustify;
+
+
+gHTMLAttr.h5 =
+[
+  "align",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.h5_align = gHAlignJustify;
+
+gHTMLAttr.h6 =
+[
+  "align",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.h6_align = gHAlignJustify;
+
+gHTMLAttr.head =
+[
+  "profile",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.hr =
+[
+  "align",
+  "noshade",
+  "#size",
+  "%width",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.hr_align = gHAlign;
+
+gHTMLAttr.hr_noshade = 
+[
+  "noshade"
+];
+
+
+gHTMLAttr.html =
+[
+  "version",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.i =
+[
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.iframe =
+[
+  "longdesc",
+  "name",
+  "src",
+  "$frameborder",
+  "marginwidth",
+  "marginheight",
+  "$scrolling",
+  "align",
+  "%height",
+  "%width",
+  "-",
+  "_core"
+];
+
+gHTMLAttr.iframe_frameborder =
+[
+  "1",
+  "0"
+];
+
+gHTMLAttr.iframe_scrolling =
+[
+  "auto",
+  "yes",
+  "no"
+];
+
+gHTMLAttr.iframe_align =
+[
+  "top",
+  "middle",
+  "bottom",
+  "left",
+  "right"
+];
+
+gHTMLAttr.img =
+[
+  "$src",
+  "$alt",
+  "longdesc",
+  "name",
+  "%height",
+  "%width",
+  "usemap",
+  "ismap",
+  "align",
+  "#border",
+  "#hspace",
+  "#vspace",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.img_ismap =
+[
+  "ismap"
+];
+
+gHTMLAttr.img_align =
+[
+  "top",
+  "middle",
+  "bottom",
+  "left",
+  "right"
+];
+
+gHTMLAttr.input =
+[
+  "$type",
+  "name",
+  "value",
+  "checked",
+  "disabled",
+  "readonly",
+  "#size",
+  "#maxlength",
+  "src",
+  "alt",
+  "usemap",
+  "ismap",
+  "#tabindex",
+  "!accesskey",
+  "accept",
+  "align",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.input_type =
+[
+  "text",
+  "password",
+  "checkbox",
+  "radio",
+  "submit",
+  "reset",
+  "file",
+  "hidden",
+  "image",
+  "button"
+];
+
+gHTMLAttr.input_checked =
+[
+  "checked"
+];
+
+gHTMLAttr.input_disabled =
+[
+  "disabled"
+];
+
+gHTMLAttr.input_readonly =
+[
+  "readonly"
+];
+
+
+gHTMLAttr.input_ismap =
+[
+  "ismap"
+];
+
+
+gHTMLAttr.input_align =
+[
+  "top",
+  "middle",
+  "bottom",
+  "left",
+  "right"
+];
+
+gHTMLAttr.ins =
+[
+  "cite",
+  "datetime",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.isindex =
+[
+  "prompt",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.kbd =
+[
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.label =
+[
+  "for",
+  "!accesskey",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.legend =
+[
+  "!accesskey",
+  "align",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.legend_align =
+[
+  "top",
+  "bottom",
+  "left",
+  "right"
+];
+
+gHTMLAttr.li =
+[
+  "type",
+  "#value",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.li_type =
+[
+  "disc",
+  "square",
+  "circle",
+  "-",
+  "1",
+  "a",
+  "A",
+  "i",
+  "I"
+];
+
+gHTMLAttr.link =
+[
+  "charset",
+  "href",
+  "^hreflang",
+  "type",
+  "rel",
+  "rev",
+  "media",
+  "target",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.link_target = gTarget;
+
+gHTMLAttr.link_rel =
+[
+  "alternate",
+  "stylesheet",
+  "start",
+  "next",
+  "prev",
+  "contents",
+  "index",
+  "glossary",
+  "copyright",
+  "chapter",
+  "section",
+  "subsection",
+  "appendix",
+  "help",
+  "bookmark"
+];
+
+gHTMLAttr.link_rev =
+[
+  "alternate",
+  "stylesheet",
+  "start",
+  "next",
+  "prev",
+  "contents",
+  "index",
+  "glossary",
+  "copyright",
+  "chapter",
+  "section",
+  "subsection",
+  "appendix",
+  "help",
+  "bookmark"
+];
+
+gHTMLAttr.map =
+[
+  "$name",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.menu =
+[
+  "compact",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.menu_compact =
+[
+  "compact"
+];
+
+gHTMLAttr.meta =
+[
+  "http-equiv",
+  "name",
+  "$content",
+  "scheme",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.noframes =
+[
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.noscript =
+[
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.object =
+[
+  "declare",
+  "classid",
+  "codebase",
+  "data",
+  "type",
+  "codetype",
+  "archive",
+  "standby",
+  "%height",
+  "%width",
+  "usemap",
+  "name",
+  "#tabindex",
+  "align",
+  "#border",
+  "#hspace",
+  "#vspace",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.object_declare =
+[
+  "declare"
+];
+
+gHTMLAttr.object_align =
+[
+  "top",
+  "middle",
+  "bottom",
+  "left",
+  "right"
+];
+
+gHTMLAttr.ol =
+[
+  "type",
+  "compact",
+  "#start",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.ol_type =
+[
+  "1",
+  "a",
+  "A",
+  "i",     
+  "I"
+];
+
+gHTMLAttr.ol_compact =
+[
+  "compact"
+];
+
+
+gHTMLAttr.optgroup =
+[
+  "disabled",
+  "$label",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.optgroup_disabled =
+[
+  "disabled"
+];
+
+
+gHTMLAttr.option =
+[
+  "selected",
+  "disabled",
+  "label",
+  "value",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.option_selected =
+[
+  "selected"
+];
+
+gHTMLAttr.option_disabled =
+[
+  "disabled"
+];
+
+
+gHTMLAttr.p =
+[
+  "align",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.p_align = gHAlignJustify;
+
+gHTMLAttr.param =
+[
+  "^id",
+  "$name",
+  "value",
+  "$valuetype",
+  "type"
+];
+
+gHTMLAttr.param_valuetype =
+[
+  "data",
+  "ref",
+  "object"
+];
+
+
+gHTMLAttr.pre =
+[
+  "%width",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.q =
+[
+  "cite",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.s =
+[
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.samp =
+[
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.script =
+[
+  "charset",
+  "$type",
+  "language",
+  "src",
+  "defer"
+];
+
+gHTMLAttr.script_defer =
+[
+  "defer"
+];
+
+
+gHTMLAttr.select =
+[
+  "name",
+  "#size",
+  "multiple",
+  "disabled",
+  "#tabindex",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.select_multiple =
+[
+  "multiple"
+];
+
+gHTMLAttr.select_disabled =
+[
+  "disabled"
+];
+
+gHTMLAttr.small =
+[
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.span =
+[
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.strike =
+[
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.strong =
+[
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.style =
+[
+  "$type",
+  "media",
+  "title",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.sub =
+[
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.sup =
+[
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.table =
+[
+  "summary",
+  "%width",
+  "#border",
+  "frame",
+  "rules",
+  "#cellspacing",
+  "#cellpadding",
+  "align",
+  "bgcolor",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.table_frame =
+[
+  "void",
+  "above",
+  "below",
+  "hsides",
+  "lhs",
+  "rhs",
+  "vsides",
+  "box",
+  "border"
+];
+
+gHTMLAttr.table_rules =
+[
+  "none",
+  "groups",
+  "rows",
+  "cols",
+  "all"
+];
+
+// Note; This is alignment of the table,
+//  not table contents, like all other table child elements
+gHTMLAttr.table_align = gHAlign;
+
+gHTMLAttr.table_bgcolor = gHTMLColors;
+
+gHTMLAttr.tbody =
+[
+  "align",
+  "!char",
+  "#charoff",
+  "valign",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.tbody_align = gHAlignTableContent;
+
+gHTMLAttr.tbody_valign = gVAlignTable;
+
+gHTMLAttr.td =
+[
+  "abbr",
+  "axis",
+  "headers",
+  "scope",
+  "$#rowspan",
+  "$#colspan",
+  "align",
+  "!char",
+  "#charoff",
+  "valign",
+  "nowrap",
+  "bgcolor",
+  "%width",
+  "%height",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.td_scope =
+[
+  "row",
+  "col",
+  "rowgroup",
+  "colgroup"
+];
+
+gHTMLAttr.td_rowspan =
+[
+  "1" // default
+];
+
+gHTMLAttr.td_colspan =
+[
+  "1" // default
+];
+
+gHTMLAttr.td_align = gHAlignTableContent;
+
+gHTMLAttr.td_valign = gVAlignTable;
+
+gHTMLAttr.td_nowrap =
+[
+  "nowrap"
+];
+
+gHTMLAttr.td_bgcolor = gHTMLColors;
+
+gHTMLAttr.textarea =
+[
+  "name",
+  "$#rows",
+  "$#cols",
+  "disabled",
+  "readonly",
+  "#tabindex",
+  "!accesskey",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.textarea_disabled =
+[
+  "disabled"
+];
+
+gHTMLAttr.textarea_readonly =
+[
+  "readonly"
+];
+
+
+gHTMLAttr.tfoot =
+[
+  "align",
+  "!char",
+  "#charoff",
+  "valign",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.tfoot_align = gHAlignTableContent;
+
+gHTMLAttr.tfoot_valign = gVAlignTable;
+
+gHTMLAttr.th =
+[
+  "abbr",
+  "axis",
+  "headers",
+  "scope",
+  "$#rowspan",
+  "$#colspan",
+  "align",
+  "!char",
+  "#charoff",
+  "valign",
+  "nowrap",
+  "bgcolor",
+  "%width",
+  "%height",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.th_scope =
+[
+  "row",
+  "col",
+  "rowgroup",
+  "colgroup"
+];
+
+gHTMLAttr.th_rowspan =
+[
+  "1" // default
+];
+
+gHTMLAttr.th_colspan =
+[
+  "1" // default
+];
+
+gHTMLAttr.th_align = gHAlignTableContent;
+
+gHTMLAttr.th_valign = gVAlignTable;
+
+gHTMLAttr.th_nowrap =
+[
+  "nowrap"
+];
+
+gHTMLAttr.th_bgcolor = gHTMLColors;
+
+gHTMLAttr.thead =
+[
+  "align",
+  "!char",
+  "#charoff",
+  "valign",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.thead_align = gHAlignTableContent;
+
+gHTMLAttr.thead_valign = gVAlignTable;
+
+gHTMLAttr.title =
+[
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.tr =
+[
+  "align",
+  "!char",
+  "#charoff",
+  "valign",
+  "bgcolor",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.tr_align = gHAlignTableContent;
+
+gHTMLAttr.tr_valign = gVAlignTable;
+
+gHTMLAttr.tr_bgcolor = gHTMLColors;
+
+gHTMLAttr.tt =
+[
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.u =
+[
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+gHTMLAttr.ul =
+[
+  "type",
+  "compact",
+  "-",
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+gHTMLAttr.ul_type =
+[
+  "disc",
+  "square",
+  "circle"
+];
+
+gHTMLAttr.ul_compact =
+[
+  "compact"
+];
+
+
+// Prefix with "_" since this is reserved (it's stripped out)
+gHTMLAttr._var =
+[
+  "_core",
+  "-",
+  "^lang",
+  "dir"
+];
+
+// ================ JS Attributes ================ //
+// These are element specif even handlers. 
+/* Most all elements use gCoreJSEvents, so those 
+   are assumed except for those listed here with "noEvents"
+*/
+
+gJSAttr.a =
+[
+  "onfocus",
+  "onblur"
+];
+
+gJSAttr.area =
+[
+  "onfocus",
+  "onblur"
+];
+
+gJSAttr.body =
+[
+  "onload",
+  "onupload"
+];
+
+gJSAttr.button =
+[
+  "onfocus",
+  "onblur"
+];
+
+gJSAttr.form =
+[
+  "onsubmit",
+  "onreset"
+];
+
+gJSAttr.frameset =
+[
+  "onload",
+  "onunload"
+];
+
+gJSAttr.input =
+[
+  "onfocus",
+  "onblur",
+  "onselect",
+  "onchange"
+];
+
+gJSAttr.label =
+[
+  "onfocus",
+  "onblur"
+];
+
+gJSAttr.select =
+[
+  "onfocus",
+  "onblur",
+  "onchange"
+];
+
+gJSAttr.textarea =
+[
+  "onfocus",
+  "onblur",
+  "onselect",
+  "onchange"
+];
+
+// Elements that don't have JSEvents:
+gJSAttr.font =
+[
+  "noJSEvents"
+];
+
+gJSAttr.applet =
+[
+  "noJSEvents"
+];
+
+gJSAttr.isindex =
+[
+  "noJSEvents"
+];
+
+gJSAttr.iframe =
+[
+  "noJSEvents"
+];
+
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdAECSSAttributes.js
@@ -0,0 +1,185 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Ben "Count XULula" Goodger
+ *   Daniel Glazman <glazman@netscape.com>
+ *   Charles Manske (cmanske@netscape.com)
+ *   Neil Rashbrook <neil@parkwaycc.co.uk>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// build attribute list in tree form from element attributes
+function BuildCSSAttributeTable()
+{
+  var style = gElement.style;
+  if (style == undefined)
+  {
+    dump("Inline styles undefined\n");
+    return;
+  }
+
+  var declLength = style.length;
+
+  if (declLength == undefined || declLength == 0)
+  {
+    if (declLength == undefined) {
+      dump("Failed to query the number of inline style declarations\n");
+    }
+
+    return;
+  }
+
+  if (declLength > 0)
+  {
+    for (var i = 0; i < declLength; ++i)
+    {
+      var name = style.item(i);
+      var value = style.getPropertyValue(name);
+      AddTreeItem( name, value, "CSSAList", CSSAttrs );
+    }
+  }
+
+  ClearCSSInputWidgets();
+}
+
+function onChangeCSSAttribute()
+{
+  var name = TrimString(gDialog.AddCSSAttributeNameInput.value);
+  if ( !name )
+    return;
+
+  var value = TrimString(gDialog.AddCSSAttributeValueInput.value);
+
+  // First try to update existing attribute
+  // If not found, add new attribute
+  if ( !UpdateExistingAttribute( name, value, "CSSAList" ) && value)
+    AddTreeItem( name, value, "CSSAList", CSSAttrs );
+}
+
+function ClearCSSInputWidgets()
+{
+  gDialog.AddCSSAttributeTree.view.selection.clearSelection();
+  gDialog.AddCSSAttributeNameInput.value ="";
+  gDialog.AddCSSAttributeValueInput.value = "";
+  SetTextboxFocus(gDialog.AddCSSAttributeNameInput);
+}
+
+function onSelectCSSTreeItem()
+{
+  if (!gDoOnSelectTree)
+    return;
+
+  var tree = gDialog.AddCSSAttributeTree;
+  if (tree && tree.view.selection.count)
+  {
+    gDialog.AddCSSAttributeNameInput.value = GetTreeItemAttributeStr(getSelectedItem(tree));
+    gDialog.AddCSSAttributeValueInput.value = GetTreeItemValueStr(getSelectedItem(tree));
+  }
+}
+
+function onInputCSSAttributeName()
+{
+  var attName = TrimString(gDialog.AddCSSAttributeNameInput.value).toLowerCase();
+  var newValue = "";
+
+  var existingValue = GetAndSelectExistingAttributeValue(attName, "CSSAList");
+  if (existingValue)
+    newValue = existingValue;
+
+  gDialog.AddCSSAttributeValueInput.value = newValue;
+}
+
+function editCSSAttributeValue(targetCell)
+{
+  if (IsNotTreeHeader(targetCell))
+    gDialog.AddCSSAttributeValueInput.inputField.select();
+}
+
+function UpdateCSSAttributes()
+{
+  var CSSAList = document.getElementById("CSSAList");
+  var styleString = "";
+  for(var i = 0; i < CSSAList.childNodes.length; i++)
+  {
+    var item = CSSAList.childNodes[i];
+    var name = GetTreeItemAttributeStr(item);
+    var value = GetTreeItemValueStr(item);
+    // this code allows users to be sloppy in typing in values, and enter
+    // things like "foo: " and "bar;". This will trim off everything after the
+    // respective character.
+    if (name.indexOf(":") != -1)
+      name = name.substring(0,name.lastIndexOf(":"));
+    if (value.indexOf(";") != -1)
+      value = value.substring(0,value.lastIndexOf(";"));
+    if (i == (CSSAList.childNodes.length - 1))
+      styleString += name + ": " + value + ";";   // last property
+    else
+      styleString += name + ": " + value + "; ";
+  }
+  if (styleString)
+  {
+    // Use editor transactions if modifying the element directly in the document
+    doRemoveAttribute("style");
+    doSetAttribute("style", styleString);  // NOTE BUG 18894!!!
+  } 
+  else if (gElement.getAttribute("style"))
+    doRemoveAttribute("style");
+}
+
+function RemoveCSSAttribute()
+{
+  var treechildren = gDialog.AddCSSAttributeTree.lastChild;
+
+  // We only allow 1 selected item
+  if (gDialog.AddCSSAttributeTree.view.selection.count)
+  {
+    var item = getSelectedItem(gDialog.AddCSSAttributeTree);
+
+    // Remove the item from the tree
+    // We always rebuild complete "style" string,
+    //  so no list of "removed" items 
+    treechildren.removeChild (item);
+
+    ClearCSSInputWidgets();
+  }
+}
+
+function SelectCSSTree( index )
+{
+  gDoOnSelectTree = false;
+  try {
+    gDialog.AddCSSAttributeTree.selectedIndex = index;
+  } catch (e) {}
+  gDoOnSelectTree = true;
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdAEHTMLAttributes.js
@@ -0,0 +1,417 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Ben "Count XULula" Goodger
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+function BuildHTMLAttributeNameList()
+{
+  gDialog.AddHTMLAttributeNameInput.removeAllItems();
+  
+  var elementName = gElement.localName.toLowerCase();
+  var attNames = gHTMLAttr[elementName];
+
+  if (attNames && attNames.length)
+  {
+    var menuitem;
+
+    for (var i = 0; i < attNames.length; i++)
+    {
+      var name = attNames[i];
+      var limitFirstChar;
+
+      if (name == "_core")
+      {
+        // Signal to append the common 'core' attributes.
+        for (var j = 0; j < gCoreHTMLAttr.length; j++)
+        {
+          name = gCoreHTMLAttr[j];
+
+          // "limitFirstChar" is the only filtering rule used for core attributes as of 8-20-01
+          // Add more rules if necessary          
+          limitFirstChar = name.indexOf("^") >= 0;
+          if (limitFirstChar)
+          {
+            menuitem = gDialog.AddHTMLAttributeNameInput.appendItem(name.replace(/\^/g, ""));
+            menuitem.setAttribute("limitFirstChar", "true");
+          }
+          else
+            gDialog.AddHTMLAttributeNameInput.appendItem(name);
+        }
+      }
+      else if (name == "-")
+      {
+        // Signal for separator
+        var popup = gDialog.AddHTMLAttributeNameInput.firstChild;
+        if (popup)
+        {
+          var sep = document.createElementNS(XUL_NS, "menuseparator");
+          if (sep)
+            popup.appendChild(sep);
+        }        
+      }
+      else
+      {
+        // Get information about value filtering
+        var forceOneChar = name.indexOf("!") >= 0;
+        var forceInteger = name.indexOf("#") >= 0;
+        var forceSignedInteger = name.indexOf("+") >= 0;
+        var forceIntOrPercent = name.indexOf("%") >= 0;
+        limitFirstChar = name.indexOf("\^") >= 0;
+        //var required = name.indexOf("$") >= 0;
+
+        // Strip flag characters
+        name = name.replace(/[!^#%$+]/g, "");
+
+        menuitem = gDialog.AddHTMLAttributeNameInput.appendItem(name);
+        if (menuitem)
+        {
+          // Signify "required" attributes by special style
+          //TODO: Don't do this until next version, when we add
+          //      explanatory text and an 'Autofill Required Attributes' button
+          //if (required)
+          //  menuitem.setAttribute("class", "menuitem-highlight-1");
+
+          // Set flags to filter value input
+          if (forceOneChar)
+            menuitem.setAttribute("forceOneChar","true");
+          if (limitFirstChar)
+            menuitem.setAttribute("limitFirstChar", "true");
+          if (forceInteger)
+            menuitem.setAttribute("forceInteger", "true");
+          if (forceSignedInteger)
+            menuitem.setAttribute("forceSignedInteger", "true");
+          if (forceIntOrPercent)
+            menuitem.setAttribute("forceIntOrPercent", "true");
+        }
+      }
+    }
+  }
+}
+
+// build attribute list in tree form from element attributes
+function BuildHTMLAttributeTable()
+{
+  var nodeMap = gElement.attributes;
+  var i;
+  if (nodeMap.length > 0) 
+  {
+    var added = false;
+    for(i = 0; i < nodeMap.length; i++)
+    {
+      if ( CheckAttributeNameSimilarity( nodeMap[i].nodeName, HTMLAttrs ) ||
+          IsEventHandler( nodeMap[i].nodeName ) ||
+          TrimString( nodeMap[i].nodeName.toLowerCase() ) == "style" ) {
+        continue;   // repeated or non-HTML attribute, ignore this one and go to next
+      }
+      var name  = nodeMap[i].name.toLowerCase();
+      if ( name.indexOf("_moz") != 0 &&
+           AddTreeItem(name, nodeMap[i].value, "HTMLAList", HTMLAttrs) )
+      {
+        added = true;
+      }
+    }
+
+    if (added)
+      SelectHTMLTree(0);
+  }
+}
+
+// add or select an attribute in the tree widget
+function onChangeHTMLAttribute()
+{
+  var name = TrimString(gDialog.AddHTMLAttributeNameInput.value);
+  if (!name)
+    return;
+
+  var value = TrimString(gDialog.AddHTMLAttributeValueInput.value);
+
+  // First try to update existing attribute
+  // If not found, add new attribute
+  if (!UpdateExistingAttribute( name, value, "HTMLAList" ) && value)
+    AddTreeItem (name, value, "HTMLAList", HTMLAttrs);
+}
+
+function ClearHTMLInputWidgets()
+{
+  gDialog.AddHTMLAttributeTree.view.selection.clearSelection();
+  gDialog.AddHTMLAttributeNameInput.value ="";
+  gDialog.AddHTMLAttributeValueInput.value = "";
+  SetTextboxFocus(gDialog.AddHTMLAttributeNameInput);
+}
+
+function onSelectHTMLTreeItem()
+{
+  if (!gDoOnSelectTree)
+    return;
+
+  var tree = gDialog.AddHTMLAttributeTree;
+  if (tree && tree.view.selection.count)
+  {
+    var inputName = TrimString(gDialog.AddHTMLAttributeNameInput.value).toLowerCase();
+    var selectedItem = getSelectedItem(tree);
+    var selectedName = selectedItem.firstChild.firstChild.getAttribute("label");
+
+    if (inputName == selectedName)
+    {
+      // Already editing selected name - just update the value input
+      gDialog.AddHTMLAttributeValueInput.value = GetTreeItemValueStr(selectedItem);
+    }
+    else
+    {
+      gDialog.AddHTMLAttributeNameInput.value = selectedName;
+
+      // Change value input based on new selected name
+      onInputHTMLAttributeName();
+    }
+  }
+}
+
+function onInputHTMLAttributeName()
+{
+  var attName = TrimString(gDialog.AddHTMLAttributeNameInput.value).toLowerCase();
+
+  // Clear value widget, but prevent triggering update in tree
+  gUpdateTreeValue = false;
+  gDialog.AddHTMLAttributeValueInput.value = "";
+  gUpdateTreeValue = true; 
+
+  if (attName)
+  {
+    // Get value list for current attribute name
+    var valueListName;
+
+    // Most elements have the "dir" attribute,
+    //   so we have just one array for the allowed values instead
+    //   requiring duplicate entries for each element in EdAEAttributes.js
+    if (attName == "dir")
+      valueListName = "all_dir";
+    else
+      valueListName = gElement.localName.toLowerCase() + "_" + attName;
+
+    // Strip off leading "_" we sometimes use (when element name is reserved word)
+    if (valueListName[0] == "_")
+      valueListName = valueListName.slice(1);
+
+    var newValue = "";
+    var listLen = 0;
+
+    // Index to which widget we were using to edit the value
+    var deckIndex = gDialog.AddHTMLAttributeValueDeck.getAttribute("selectedIndex");
+
+    if (valueListName in gHTMLAttr)
+    {
+      var valueList = gHTMLAttr[valueListName];
+
+      listLen = valueList.length;
+      if (listLen > 0)
+        newValue = valueList[0];
+
+      // Note: For case where "value list" is actually just 
+      // one (default) item, don't use menulist for that
+      if (listLen > 1)
+      {
+        gDialog.AddHTMLAttributeValueMenulist.removeAllItems();
+
+        if (deckIndex != "1")
+        {
+          // Switch to using editable menulist
+          gDialog.AddHTMLAttributeValueInput = gDialog.AddHTMLAttributeValueMenulist;
+          gDialog.AddHTMLAttributeValueDeck.setAttribute("selectedIndex", "1");
+        }
+        // Rebuild the list
+        for (var i = 0; i < listLen; i++)
+        {
+          if (valueList[i] == "-")
+          {
+            // Signal for separator
+            var popup = gDialog.AddHTMLAttributeValueInput.firstChild;
+            if (popup)
+            {
+              var sep = document.createElementNS(XUL_NS, "menuseparator");
+              if (sep)
+                popup.appendChild(sep);
+            }        
+          } else {
+            gDialog.AddHTMLAttributeValueMenulist.appendItem(valueList[i]);
+          }
+        }
+      }
+    }
+    
+    if (listLen <= 1 && deckIndex != "0")
+    {
+      // No list: Use textbox for input instead
+      gDialog.AddHTMLAttributeValueInput = gDialog.AddHTMLAttributeValueTextbox;
+      gDialog.AddHTMLAttributeValueDeck.setAttribute("selectedIndex", "0");
+    }
+
+    // If attribute already exists in tree, use associated value,
+    //  else use default found above
+    var existingValue = GetAndSelectExistingAttributeValue(attName, "HTMLAList");
+    if (existingValue)
+      newValue = existingValue;
+      
+    gDialog.AddHTMLAttributeValueInput.value = newValue;
+  }
+}
+
+function onInputHTMLAttributeValue()
+{
+  if (!gUpdateTreeValue)
+    return;
+
+  var name = TrimString(gDialog.AddHTMLAttributeNameInput.value);
+  if (!name)
+    return;
+
+  // Trim spaces only from left since we must allow spaces within the string
+  //  (we always reset the input field's value below)
+  var value = TrimStringLeft(gDialog.AddHTMLAttributeValueInput.value);
+  if (value)
+  {
+    // Do value filtering based on type of attribute
+    // (Do not use "forceInteger()" to avoid multiple
+    //  resetting of input's value and flickering)
+    var selectedItem = gDialog.AddHTMLAttributeNameInput.selectedItem;
+
+    if (selectedItem)
+    {
+      if ( selectedItem.getAttribute("forceOneChar") == "true" &&
+           value.length > 1 )
+        value = value.slice(0, 1);
+
+      if ( selectedItem.getAttribute("forceIntOrPercent") == "true" )
+      {
+        // Allow integer with optional "%" as last character
+        var percent = TrimStringRight(value).slice(-1);
+        value = value.replace(/\D+/g,"");
+        if (percent == "%")
+          value += percent;
+      }
+      else if ( selectedItem.getAttribute("forceInteger") == "true" )
+      {
+        value = value.replace(/\D+/g,"");
+      }
+      else if ( selectedItem.getAttribute("forceSignedInteger") == "true" )
+      {
+        // Allow integer with optional "+" or "-" as first character
+        var sign = value[0];
+        value = value.replace(/\D+/g,"");
+        if (sign == "+" || sign == "-")
+          value = sign + value;
+      }
+      
+      // Special case attributes 
+      if (selectedItem.getAttribute("limitFirstChar") == "true")
+      {
+        // Limit first character to letter, and all others to 
+        //  letters, numbers, and a few others
+        value = value.replace(/^[^a-zA-Z\u0080-\uFFFF]/, "").replace(/[^a-zA-Z0-9_\.\-\:\u0080-\uFFFF]+/g,'');
+      }
+
+      // Update once only if it changed
+      if (value != gDialog.AddHTMLAttributeValueInput.value)
+        gDialog.AddHTMLAttributeValueInput.value = value;
+    }
+  }
+
+  // Update value in the tree list
+  // If not found, add new attribute
+  if ( !UpdateExistingAttribute(name, value, "HTMLAList" ) && value)
+    AddTreeItem(name, value, "HTMLAList", HTMLAttrs);
+}
+
+function editHTMLAttributeValue(targetCell)
+{
+  if (IsNotTreeHeader(targetCell))
+    gDialog.AddHTMLAttributeValueInput.inputField.select();
+}
+
+
+// update the object with added and removed attributes
+function UpdateHTMLAttributes()
+{
+  var HTMLAList = document.getElementById("HTMLAList");
+  var i;
+
+  // remove removed attributes
+  for (i = 0; i < HTMLRAttrs.length; i++)
+  {
+    var name = HTMLRAttrs[i];
+
+    if (gElement.hasAttribute(name))
+      doRemoveAttribute(name);
+  }
+
+  // Set added or changed attributes
+  for( i = 0; i < HTMLAList.childNodes.length; i++)
+  {
+    var item = HTMLAList.childNodes[i];
+    doSetAttribute( GetTreeItemAttributeStr(item), GetTreeItemValueStr(item));
+  }
+}
+
+function RemoveHTMLAttribute()
+{
+  var treechildren = gDialog.AddHTMLAttributeTree.lastChild;
+
+  // We only allow 1 selected item
+  if (gDialog.AddHTMLAttributeTree.view.selection.count)
+  {
+    var item = getSelectedItem(gDialog.AddHTMLAttributeTree);
+    var attr = GetTreeItemAttributeStr(item);
+
+    // remove the item from the attribute array
+    HTMLRAttrs[HTMLRAttrs.length] = attr;
+    RemoveNameFromAttArray(attr, HTMLAttrs);
+
+    // Remove the item from the tree
+    treechildren.removeChild(item);
+
+    // Clear inputs and selected item in tree
+    ClearHTMLInputWidgets();
+  }
+}
+
+function SelectHTMLTree( index )
+{
+
+  gDoOnSelectTree = false;
+  try {
+    gDialog.AddHTMLAttributeTree.selectedIndex = index;
+  } catch (e) {}
+  gDoOnSelectTree = true;
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdAEJSEAttributes.js
@@ -0,0 +1,239 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Ben "Count XULula" Goodger
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+function BuildJSEAttributeNameList()
+{
+  gDialog.AddJSEAttributeNameList.removeAllItems();
+  
+  // Get events specific to current element
+  var elementName = gElement.localName.toLowerCase();
+  if (elementName in gJSAttr)
+  {
+    var attNames = gJSAttr[elementName];
+    var i;
+    var popup;
+    var sep;
+
+    if (attNames && attNames.length)
+    {
+      // Since we don't allow user-editable JS events yet (but we will soon)
+      //  simply remove the JS tab to not allow adding JS events
+      if (attNames[0] == "noJSEvents")
+      {
+        var tab = document.getElementById("tabJSE");
+        if (tab)
+          tab.parentNode.removeChild(tab);
+
+        return;
+      }
+
+      for (i = 0; i < attNames.length; i++)
+        gDialog.AddJSEAttributeNameList.appendItem(attNames[i], attNames[i]);
+
+      popup = gDialog.AddJSEAttributeNameList.firstChild;
+      if (popup)
+      {
+        sep = document.createElementNS(XUL_NS, "menuseparator");
+        if (sep)
+          popup.appendChild(sep);
+      }        
+    }
+  }
+
+  // Always add core JS events unless we aborted above
+  for (i = 0; i < gCoreJSEvents.length; i++)
+  {
+    if (gCoreJSEvents[i] == "-")
+    {
+      if (!popup)
+        popup = gDialog.AddJSEAttributeNameList.firstChild;
+
+      sep = document.createElementNS(XUL_NS, "menuseparator");
+
+      if (popup && sep)
+        popup.appendChild(sep);
+    }
+    else
+      gDialog.AddJSEAttributeNameList.appendItem(gCoreJSEvents[i], gCoreJSEvents[i]);
+  }
+  
+  gDialog.AddJSEAttributeNameList.selectedIndex = 0;
+
+  // Use current name and value of first tree item if it exists
+  onSelectJSETreeItem();
+}
+
+// build attribute list in tree form from element attributes
+function BuildJSEAttributeTable()
+{
+  var nodeMap = gElement.attributes;
+  if (nodeMap.length > 0)
+  {
+    var added = false;
+    for (var i = 0; i < nodeMap.length; i++)
+    {
+      if( CheckAttributeNameSimilarity( nodeMap[i].nodeName, JSEAttrs ) )
+        continue;   // repeated or non-JS handler, ignore this one and go to next
+      if( !IsEventHandler( nodeMap[i].nodeName ) )
+        continue; // attribute isn't an event handler.
+      var name  = nodeMap[i].nodeName.toLowerCase();
+      var value = gElement.getAttribute(nodeMap[i].nodeName);
+      if (AddTreeItem( name, value, "JSEAList", JSEAttrs )) // add item to tree
+        added = true;
+    }
+
+    // Select first item
+    if (added)
+      gDialog.AddJSEAttributeTree.selectedIndex = 0;
+  }
+}
+
+// check to see if given string is an event handler.
+function IsEventHandler( which )
+{
+  var handlerName = which.toLowerCase();
+  var firstTwo = handlerName.substring(0,2);
+  if (firstTwo == "on")
+    return true;
+  else
+    return false;
+}
+
+function onSelectJSEAttribute()
+{
+  if(!gDoOnSelectTree)
+    return;
+
+  gDialog.AddJSEAttributeValueInput.value = 
+      GetAndSelectExistingAttributeValue(gDialog.AddJSEAttributeNameList.label, "JSEAList");
+}
+
+function onSelectJSETreeItem()
+{
+  var tree = gDialog.AddJSEAttributeTree;
+  if (tree && tree.view.selection.count)
+  {
+    // Select attribute name in list
+    gDialog.AddJSEAttributeNameList.value = GetTreeItemAttributeStr(getSelectedItem(tree));
+
+    // Set value input to that in tree (no need to update this in the tree)
+    gUpdateTreeValue = false;
+    gDialog.AddJSEAttributeValueInput.value =  GetTreeItemValueStr(getSelectedItem(tree));
+    gUpdateTreeValue = true;
+  }
+}
+
+function onInputJSEAttributeValue()
+{
+  if (gUpdateTreeValue)
+  {
+
+    var name = TrimString(gDialog.AddJSEAttributeNameList.label);
+    var value = TrimString(gDialog.AddJSEAttributeValueInput.value);
+
+    // Update value in the tree list
+    // Since we have a non-editable menulist, 
+    //   we MUST automatically add the event attribute if it doesn't exist
+    if (!UpdateExistingAttribute( name, value, "JSEAList" ) && value)
+      AddTreeItem( name, value, "JSEAList", JSEAttrs );
+  }
+}
+
+function editJSEAttributeValue(targetCell)
+{
+  if (IsNotTreeHeader(targetCell))
+    gDialog.AddJSEAttributeValueInput.inputField.select();
+}
+
+function UpdateJSEAttributes()
+{
+  var JSEAList = document.getElementById("JSEAList");
+  var i;
+
+  // remove removed attributes
+  for (i = 0; i < JSERAttrs.length; i++)
+  {
+    var name = JSERAttrs[i];
+
+    if (gElement.hasAttribute(name))
+      doRemoveAttribute(name);
+  }
+
+  // Add events
+  for (i = 0; i < JSEAList.childNodes.length; i++)
+  {
+    var item = JSEAList.childNodes[i];
+
+    // set the event handler
+    doSetAttribute( GetTreeItemAttributeStr(item), GetTreeItemValueStr(item) );
+  }
+}
+
+function RemoveJSEAttribute()
+{
+  var treechildren = gDialog.AddJSEAttributeTree.lastChild;
+
+  // This differs from HTML and CSS panels: 
+  // We reselect after removing, because there is not
+  //  editable attribute name input, so we can't clear that
+  //  like we do in other panels
+  var newIndex = gDialog.AddJSEAttributeTree.selectedIndex;
+
+  // We only allow 1 selected item
+  if (gDialog.AddJSEAttributeTree.view.selection.count)
+  {
+    var item = getSelectedItem(gDialog.AddJSEAttributeTree);
+
+    // Name is the text of the treecell
+    var attr = GetTreeItemAttributeStr(item);
+
+    // remove the item from the attribute array
+    if (newIndex >= (JSEAttrs.length-1))
+      newIndex--;
+
+    // remove the item from the attribute array
+    JSERAttrs[JSERAttrs.length] = attr;
+    RemoveNameFromAttArray(attr, JSEAttrs);
+
+    // Remove the item from the tree
+    treechildren.removeChild (item);
+
+    // Reselect an item
+    gDialog.AddJSEAttributeTree.selectedIndex = newIndex;
+  }
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdAdvancedEdit.js
@@ -0,0 +1,369 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Ben "Count XULula" Goodger
+ *   Charles Manske (cmanske@netscape.com)
+ *   Neil Rashbrook (neil@parkwaycc.co.uk)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**************         GLOBALS         **************/
+var gElement    = null; // handle to actual element edited
+
+var HTMLAttrs   = [];   // html attributes
+var CSSAttrs    = [];   // css attributes
+var JSEAttrs    = [];   // js events
+
+var HTMLRAttrs  = [];   // removed html attributes
+var JSERAttrs   = [];   // removed js events
+
+/* Set false to allow changing selection in tree
+   without doing "onselect" handler actions
+*/
+var gDoOnSelectTree = true;
+var gUpdateTreeValue = true;
+
+/************** INITIALISATION && SETUP **************/
+
+/**
+ * function   : void Startup();
+ * parameters : none
+ * returns    : none
+ * desc.      : startup and initialisation, prepares dialog.
+ **/
+function Startup()
+{
+  var editor = GetCurrentEditor();
+
+  // Element to edit is passed in
+  if (!editor || !window.arguments[1])
+  {
+    dump("Advanced Edit: No editor or element to edit not supplied\n");
+    window.close();
+    return;
+  }
+  // This is the return value for the parent,
+  // who only needs to know if OK was clicked
+  window.opener.AdvancedEditOK = false;
+
+  // The actual element edited (not a copy!)
+  gElement = window.arguments[1];
+
+  // place the tag name in the header
+  var tagLabel = document.getElementById("tagLabel");
+  tagLabel.setAttribute("value", ("<" + gElement.localName + ">"));
+
+  // Create dialog object to store controls for easy access
+  gDialog.AddHTMLAttributeNameInput  = document.getElementById("AddHTMLAttributeNameInput");
+
+  // We use a <deck> to switch between editable menulist and textbox
+  gDialog.AddHTMLAttributeValueDeck     = document.getElementById("AddHTMLAttributeValueDeck");
+  gDialog.AddHTMLAttributeValueMenulist = document.getElementById("AddHTMLAttributeValueMenulist");
+  gDialog.AddHTMLAttributeValueTextbox  = document.getElementById("AddHTMLAttributeValueTextbox");
+  gDialog.AddHTMLAttributeValueInput    = gDialog.AddHTMLAttributeValueTextbox;
+
+  gDialog.AddHTMLAttributeTree          = document.getElementById("HTMLATree");
+  gDialog.AddCSSAttributeNameInput      = document.getElementById("AddCSSAttributeNameInput");
+  gDialog.AddCSSAttributeValueInput     = document.getElementById("AddCSSAttributeValueInput");
+  gDialog.AddCSSAttributeTree           = document.getElementById("CSSATree");
+  gDialog.AddJSEAttributeNameList       = document.getElementById("AddJSEAttributeNameList");
+  gDialog.AddJSEAttributeValueInput     = document.getElementById("AddJSEAttributeValueInput");
+  gDialog.AddJSEAttributeTree           = document.getElementById("JSEATree");
+  gDialog.okButton                      = document.documentElement.getButton("accept");
+
+  // build the attribute trees
+  BuildHTMLAttributeTable();
+  BuildCSSAttributeTable();
+  BuildJSEAttributeTable();
+  
+  // Build attribute name arrays for menulists
+  BuildJSEAttributeNameList();
+  BuildHTMLAttributeNameList();
+  // No menulists for CSS panel (yet)
+
+  // Set focus to Name editable menulist in HTML panel
+  SetTextboxFocus(gDialog.AddHTMLAttributeNameInput);
+
+  // size the dialog properly
+  window.sizeToContent();
+
+  SetWindowLocation();
+}
+
+/**
+ * function   : bool onAccept ( void );
+ * parameters : none
+ * returns    : boolean true to close the window
+ * desc.      : event handler for ok button
+ **/
+function onAccept()
+{
+  var editor = GetCurrentEditor();
+  editor.beginTransaction();
+  try {
+    // Update our gElement attributes
+    UpdateHTMLAttributes();
+    UpdateCSSAttributes();
+    UpdateJSEAttributes();
+  } catch(ex) {
+    dump(ex);
+  }
+  editor.endTransaction();
+
+  window.opener.AdvancedEditOK = true;
+  SaveWindowLocation();
+
+  return true; // do close the window
+}
+
+// Helpers for removing and setting attributes
+// Use editor transactions if modifying the element already in the document
+// (Temporary element from a property dialog won't have a parent node)
+function doRemoveAttribute(attrib)
+{
+  try {
+    var editor = GetCurrentEditor();
+    if (gElement.parentNode)
+      editor.removeAttribute(gElement, attrib);
+    else
+      gElement.removeAttribute(attrib);
+  } catch(ex) {}
+}
+
+function doSetAttribute(attrib, value)
+{
+  try {
+    var editor = GetCurrentEditor();
+    if (gElement.parentNode)
+      editor.setAttribute(gElement, attrib, value);
+    else
+      gElement.setAttribute(attrib, value);
+  } catch(ex) {}
+}
+
+/**
+ * function   : bool CheckAttributeNameSimilarity ( string attName, array attArray );
+ * parameters : attribute to look for, array of current attributes
+ * returns    : true if attribute already exists, false if it does not
+ * desc.      : checks to see if any other attributes by the same name as the arg supplied
+ *              already exist.
+ **/
+function CheckAttributeNameSimilarity(attName, attArray)
+{
+  for (var i = 0; i < attArray.length; i++)
+  {
+    if (attName.toLowerCase() == attArray[i].toLowerCase())
+      return true;
+  }
+  return false;
+}
+
+/**
+ * function   : bool UpdateExistingAttribute ( string attName, string attValue, string treeChildrenId );
+ * parameters : attribute to look for, new value, ID of <treeChildren> node in XUL tree
+ * returns    : true if attribute already exists in tree, false if it does not
+ * desc.      : checks to see if any other attributes by the same name as the arg supplied
+ *              already exist while setting the associated value if different from current value
+ **/
+function UpdateExistingAttribute( attName, attValue, treeChildrenId )
+{
+  var treeChildren = document.getElementById(treeChildrenId);
+  if (!treeChildren)
+    return false;
+
+  var name;
+  var i;
+  attName = TrimString(attName).toLowerCase();
+  attValue = TrimString(attValue);
+
+  for (i = 0; i < treeChildren.childNodes.length; i++)
+  {
+    var item = treeChildren.childNodes[i];
+    name = GetTreeItemAttributeStr(item);
+    if (name.toLowerCase() == attName)
+    {
+      // Set the text in the "value' column treecell
+      SetTreeItemValueStr(item, attValue);
+
+      // Select item just changed, 
+      //  but don't trigger the tree's onSelect handler
+      gDoOnSelectTree = false;
+      try {
+        selectTreeItem(treeChildren, item);
+      } catch (e) {}
+      gDoOnSelectTree = true;
+
+      return true;
+    }
+  }
+  return false;
+}
+
+/**
+ * function   : string GetAndSelectExistingAttributeValue ( string attName, string treeChildrenId );
+ * parameters : attribute to look for, ID of <treeChildren> node in XUL tree
+ * returns    : value in from the tree or empty string if name not found
+ **/
+function GetAndSelectExistingAttributeValue( attName, treeChildrenId )
+{
+  if (!attName)
+    return "";
+
+  var treeChildren = document.getElementById(treeChildrenId);
+  var name;
+  var i;
+
+  for (i = 0; i < treeChildren.childNodes.length; i++)
+  {
+    var item = treeChildren.childNodes[i];
+    name = GetTreeItemAttributeStr(item);
+    if (name.toLowerCase() == attName.toLowerCase())
+    {
+      // Select item in the tree
+      //  but don't trigger the tree's onSelect handler
+      gDoOnSelectTree = false;
+      try {
+        selectTreeItem(treeChildren, item);
+      } catch (e) {}
+      gDoOnSelectTree = true;
+
+      // Get the text in the "value' column treecell
+      return GetTreeItemValueStr(item);
+    }
+  }
+
+  // Attribute doesn't exist in tree, so remove selection
+  gDoOnSelectTree = false;
+  try {
+    treeChildren.parentNode.view.selection.clearSelection();
+  } catch (e) {}
+  gDoOnSelectTree = true;
+
+  return "";
+}
+
+/* Tree structure: 
+  <treeItem>
+    <treeRow>
+      <treeCell> // Name Cell
+      <treeCell  // Value Cell
+*/
+function GetTreeItemAttributeStr(treeItem)
+{
+  if (treeItem)
+    return TrimString(treeItem.firstChild.firstChild.getAttribute("label"));
+
+  return "";
+}
+
+function GetTreeItemValueStr(treeItem)
+{
+  if (treeItem)
+    return TrimString(treeItem.firstChild.lastChild.getAttribute("label"));
+
+  return "";
+}
+
+function SetTreeItemValueStr(treeItem, value)
+{
+  if (treeItem && GetTreeItemValueStr(treeItem) != value)
+    treeItem.firstChild.lastChild.setAttribute("label", value);
+}
+
+function IsNotTreeHeader(treeCell)
+{
+  if (treeCell)
+    return (treeCell.parentNode.parentNode.nodeName != "treehead");
+
+  return false;
+}
+
+function RemoveNameFromAttArray(attName, attArray)
+{
+  for (var i=0; i < attArray.length; i++)
+  {
+    if (attName.toLowerCase() == attArray[i].toLowerCase())
+    {
+      // Remove 1 array item
+      attArray.splice(i,1);
+      break;
+    }
+  }
+}
+
+// adds a generalised treeitem.
+function AddTreeItem ( name, value, treeChildrenId, attArray )
+{
+  attArray[attArray.length] = name;
+  var treeChildren    = document.getElementById ( treeChildrenId );
+  var treeitem    = document.createElementNS ( XUL_NS, "treeitem" );
+  var treerow     = document.createElementNS ( XUL_NS, "treerow" );
+
+  var attrCell    = document.createElementNS ( XUL_NS, "treecell" );
+  attrCell.setAttribute( "class", "propertylist" );
+  attrCell.setAttribute( "label", name );
+
+  var valueCell    = document.createElementNS ( XUL_NS, "treecell" );
+  valueCell.setAttribute( "class", "propertylist" );
+  valueCell.setAttribute( "label", value );
+
+  treerow.appendChild ( attrCell );
+  treerow.appendChild ( valueCell );
+  treeitem.appendChild ( treerow );
+  treeChildren.appendChild ( treeitem );
+
+  // Select item just added,
+  //  but suppress calling the onSelect handler
+  gDoOnSelectTree = false;
+  try {
+    selectTreeItem(treeChildren, treeitem);
+  } catch (e) {}
+  gDoOnSelectTree = true;
+
+  return treeitem;
+}
+
+function selectTreeItem(treeChildren, item)
+{
+  var index = treeChildren.parentNode.contentView.getIndexOfItem(item);
+  treeChildren.parentNode.view.selection.select(index);
+}
+
+function getSelectedItem(tree)
+{
+  if (tree.view.selection.count == 1)
+    return tree.contentView.getItemAtIndex(tree.currentIndex);
+  else
+    return null;
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdAdvancedEdit.xul
@@ -0,0 +1,220 @@
+<?xml version="1.0"?>
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -   Ben "Count XULula" Goodger
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!-- first checkin of the year 2000!      -->
+<!-- Ben Goodger, 12:50AM, 01/00/00 NZST  -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!-- May not need this here -->
+<!-- <?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?> -->
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EdAdvancedEdit.dtd">
+<dialog title="&WindowTitle.label;"
+    id="advancedEditDlg"
+    style="width: 40em;"
+    xmlns ="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    onload="Startup()"
+    buttons="accept,cancel"
+    ondialogaccept="return onAccept();"
+    ondialogcancel="return onCancel();">
+
+  <!-- Methods common to all editor dialogs -->
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <!-- element page functions -->
+  <script type="application/x-javascript" src="chrome://editor/content/EdAEHTMLAttributes.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdAECSSAttributes.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdAEJSEAttributes.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdAEAttributes.js"/>
+
+  <!-- global dialog functions -->
+  <script type="application/x-javascript" src="chrome://editor/content/EdAdvancedEdit.js"/>
+
+  <broadcaster id="args" value=""/>
+
+  <hbox>
+    <label value="&currentattributesfor.label;"/>
+    <label class="header" id="tagLabel"/>
+  </hbox>
+  
+  <separator class="thin"/>
+  
+  <tabbox flex="1">
+    <tabs>
+      <tab label="&tabHTML.label;"/>
+      <tab label="&tabCSS.label;"/>
+      <tab label="&tabJSE.label;" id="tabJSE"/>
+    </tabs>
+    <tabpanels flex="1">
+      <!-- ============================================================== -->
+      <!--                        HTML Attributes                         -->
+      <!-- ============================================================== -->
+      <vbox>
+        <tree id="HTMLATree" class="AttributesTree" flex="1"
+          hidecolumnpicker="true" seltype="single"
+          onselect="onSelectHTMLTreeItem();"
+          onclick="onSelectHTMLTreeItem();"
+          ondblclick="editHTMLAttributeValue(event.target);">
+          <treecols>
+            <treecol id="HTMLAttrCol" flex="35" label="&tree.attributeHeader.label;"/>
+            <splitter class="tree-splitter"/>
+            <treecol id="HTMLValCol" flex="65" label="&tree.valueHeader.label;"/>
+          </treecols>
+          <treechildren id="HTMLAList" class="gridlines" flex="1"/>
+        </tree>
+        <hbox align="center">
+          <label value="&editAttribute.label;"/>
+          <spacer flex="1"/>
+          <button label="&removeAttribute.label;" oncommand="RemoveHTMLAttribute();"/>
+        </hbox>
+        <grid>
+          <columns>
+            <column flex="1"/><column flex="1"/>
+          </columns>
+          <rows>
+            <row equalsize="always">
+              <label control="AddHTMLAttributeNameInput" value="&AttName.label;"/>
+              <label control="AddHTMLAttributeValueInput" value="&AttValue.label;"/>
+            </row>
+            <row align="top" equalsize="always">
+              <!-- Lists are built at runtime -->
+              <menulist id="AddHTMLAttributeNameInput" editable="true" flex="1"
+                        oninput="onInputHTMLAttributeName();"
+                        onchange="onChangeHTMLAttribute();"/>
+              <deck id="AddHTMLAttributeValueDeck" selectedIndex="0">
+                <hbox align="top">
+                  <textbox id="AddHTMLAttributeValueTextbox" flex="1"
+                           oninput="onInputHTMLAttributeValue();"/>
+                </hbox>
+                <hbox align="top">
+                  <menulist id="AddHTMLAttributeValueMenulist" editable="true" flex="1"
+                            oninput="onInputHTMLAttributeValue();"/>
+                </hbox>
+              </deck>
+            </row>
+          </rows>
+        </grid>
+      </vbox>
+      <!-- ============================================================== -->
+      <!--                         CSS Attributes                         -->
+      <!-- ============================================================== -->
+      <vbox>
+        <tree id="CSSATree" class="AttributesTree" flex="1"
+          hidecolumnpicker="true" seltype="single"
+          onselect="onSelectCSSTreeItem();"
+          onclick="onSelectCSSTreeItem();"
+          ondblclick="editCSSAttributeValue(event.target);">
+          <treecols>
+            <treecol id="CSSPropCol" flex="35" label="&tree.propertyHeader.label;"/>
+            <splitter class="tree-splitter"/>
+            <treecol id="CSSValCol" flex="65" label="&tree.valueHeader.label;"/>
+          </treecols>
+          <treechildren id="CSSAList" class="gridlines" flex="1"/>
+        </tree>
+        <hbox align="center">
+          <label value="&editAttribute.label;"/>
+          <spacer flex="1"/>
+          <button label="&removeAttribute.label;" oncommand="RemoveCSSAttribute();"/>
+        </hbox>
+        <grid>
+          <columns>
+            <column flex="1"/><column flex="1"/>
+          </columns>
+          <rows>
+            <row equalsize="always">
+              <label value="&PropertyName.label;"/>
+              <label value="&AttValue.label;"/>
+            </row>
+            <row align="top" equalsize="always">
+              <textbox id="AddCSSAttributeNameInput" flex="1"
+                oninput="onInputCSSAttributeName();"
+                onchange="onChangeCSSAttribute();"/>
+          	  <textbox id="AddCSSAttributeValueInput" flex="1"
+                oninput="onChangeCSSAttribute();"/>
+            </row>
+          </rows>
+        </grid>
+      </vbox>
+      <!-- ============================================================== -->
+      <!--                    JavaScript Event Handlers                   -->
+      <!-- ============================================================== -->
+      <vbox>
+        <tree id="JSEATree" class="AttributesTree" flex="1"
+          hidecolumnpicker="true" seltype="single"
+          onselect="onSelectJSETreeItem();"
+          onclick="onSelectJSETreeItem();"
+          ondblclick="editJSEAttributeValue(event.target);">
+          <treecols>
+            <treecol id="AttrCol" flex="35" label="&tree.attributeHeader.label;"/>
+            <splitter class="tree-splitter"/>
+            <treecol id="HeaderCol" flex="65" label="&tree.valueHeader.label;"/>
+          </treecols>
+          <treechildren id="JSEAList" class="gridlines" flex="1"/>
+        </tree>
+        <hbox align="center">
+          <label value="&editAttribute.label;"/>
+          <spacer flex="1"/>
+          <button label="&removeAttribute.label;" oncommand="RemoveJSEAttribute()"/>
+        </hbox>
+        <grid>
+          <columns>
+            <column flex="1"/><column flex="1"/>
+          </columns>
+          <rows>
+            <row equalsize="always">
+              <label value="&AttName.label;"/>
+              <label value="&AttValue.label;"/>
+            </row>
+            <row align="top" equalsize="always">
+              <!-- List is built at runtime -->
+              <menulist id="AddJSEAttributeNameList" flex="1"
+                oncommand="onSelectJSEAttribute();">
+                <menupopup/>
+              </menulist>
+          	  <textbox id="AddJSEAttributeValueInput" flex="1"
+                oninput="onInputJSEAttributeValue();"/>
+            </row>
+          </rows>
+        </grid>
+      </vbox>
+    </tabpanels>
+  </tabbox>
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdButtonProps.js
@@ -0,0 +1,178 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Button Properties Dialog.
+ *
+ * The Initial Developer of the Original Code is
+ * Neil Rashbrook.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s): Neil Rashbrook <neil@parkwaycc.co.uk>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var insertNew;
+var buttonElement;
+
+// dialog initialization code
+
+function Startup()
+{
+  var editor = GetCurrentEditor();
+  if (!editor)
+  {
+    window.close();
+    return;
+  }
+
+  gDialog = {
+    buttonType:       document.getElementById("ButtonType"),
+    buttonName:       document.getElementById("ButtonName"),
+    buttonValue:      document.getElementById("ButtonValue"),
+    buttonDisabled:   document.getElementById("ButtonDisabled"),
+    buttonTabIndex:   document.getElementById("ButtonTabIndex"),
+    buttonAccessKey:  document.getElementById("ButtonAccessKey"),
+    MoreSection:      document.getElementById("MoreSection"),
+    MoreFewerButton:  document.getElementById("MoreFewerButton"),
+    RemoveButton:     document.getElementById("RemoveButton")
+  };
+
+  // Get a single selected button element
+  const kTagName = "button";
+  try {
+    buttonElement = editor.getSelectedElement(kTagName);
+  } catch (e) {}
+
+  if (buttonElement)
+    // We found an element and don't need to insert one
+    insertNew = false;
+  else
+  {
+    insertNew = true;
+
+    // We don't have an element selected,
+    //  so create one with default attributes
+    try {
+      buttonElement = editor.createElementWithDefaults(kTagName);
+    } catch (e) {}
+
+    if (!buttonElement)
+    {
+      dump("Failed to get selected element or create a new one!\n");
+      window.close();
+      return;
+    }
+    // Hide button removing existing button
+    gDialog.RemoveButton.hidden = true;
+  }
+
+  // Make a copy to use for AdvancedEdit
+  globalElement = buttonElement.cloneNode(false);
+
+  InitDialog();
+
+  InitMoreFewer();
+
+  gDialog.buttonType.focus();
+
+  SetWindowLocation();
+}
+
+function InitDialog()
+{
+  var type = globalElement.getAttribute("type");
+  var index = 0;
+  switch (type)
+  {
+    case "button":
+      index = 2;
+      break;
+    case "reset":
+      index = 1;
+      break;
+  }
+  gDialog.buttonType.selectedIndex = index;
+  gDialog.buttonName.value = globalElement.getAttribute("name");
+  gDialog.buttonValue.value = globalElement.getAttribute("value");
+  gDialog.buttonDisabled.setAttribute("checked", globalElement.hasAttribute("disabled"));
+  gDialog.buttonTabIndex.value = globalElement.getAttribute("tabindex");
+  gDialog.buttonAccessKey.value = globalElement.getAttribute("accesskey");
+}
+
+function RemoveButton()
+{
+  RemoveContainer(buttonElement);
+  SaveWindowLocation();
+  window.close();
+}
+
+function ValidateData()
+{
+  var attributes = {
+    type: ["", "reset", "button"][gDialog.buttonType.selectedIndex],
+    name: gDialog.buttonName.value,
+    value: gDialog.buttonValue.value,
+    tabindex: gDialog.buttonTabIndex.value,
+    accesskey: gDialog.buttonAccessKey.value
+  };
+  for (var a in attributes)
+  {
+    if (attributes[a])
+      globalElement.setAttribute(a, attributes[a]);
+    else
+      globalElement.removeAttribute(a);
+  }
+  if (gDialog.buttonDisabled.checked)
+    globalElement.setAttribute("disabled", "");
+  else
+    globalElement.removeAttribute("disabled");
+  return true;
+}
+
+function onAccept()
+{
+  // All values are valid - copy to actual element in doc or
+  //   element created to insert
+  ValidateData();
+
+  var editor = GetCurrentEditor();
+
+  editor.cloneAttributes(buttonElement, globalElement);
+
+  if (insertNew)
+  {
+    if (!InsertElementAroundSelection(buttonElement))
+    {
+      buttonElement.innerHTML = editor.outputToString("text/html", kOutputSelectionOnly);
+      editor.insertElementAtSelection(buttonElement, true);
+    }
+  }
+
+  SaveWindowLocation();
+
+  return true;
+}
+
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdButtonProps.xul
@@ -0,0 +1,116 @@
+<?xml version="1.0"?>
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Button Properties Dialog.
+   -
+   - The Initial Developer of the Original Code is
+   - Neil Rashbrook.
+   - Portions created by the Initial Developer are Copyright (C) 2001
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s): Neil Rashbrook <neil@parkwaycc.co.uk>
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either the GNU General Public License Version 2 or later (the "GPL"), or
+   - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the LGPL or the GPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?> 
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorButtonProperties.dtd">
+<dialog title="&windowTitle.label;"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        onload="Startup();"
+        buttons="accept,cancel"
+        ondialogaccept="return onAccept();"
+        ondialogcancel="return onCancel();">
+
+  <!-- Methods common to all editor dialogs -->
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdButtonProps.js"/>
+
+  <broadcaster id="args" value=""/>
+  <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+  <groupbox><caption label="&Settings.label;"/>
+    <grid><columns><column/><column/></columns>
+      <rows>
+        <row align="center">
+          <label control="ButtonType" value="&ButtonType.label;" accesskey="&ButtonType.accesskey;"/>
+          <menulist id="ButtonType">
+            <menupopup>
+              <menuitem label="&submit.value;"/>
+              <menuitem label="&reset.value;"/>
+              <menuitem label="&button.value;"/>
+            </menupopup>
+          </menulist>
+        </row>
+        <row align="center">
+          <label control="ButtonName" value="&ButtonName.label;" accesskey="&ButtonName.accesskey;"/>
+          <textbox id="ButtonName"/>
+        </row>
+        <row align="center">
+          <label control="ButtonValue" value="&ButtonValue.label;" accesskey="&ButtonValue.accesskey;"/>
+          <textbox id="ButtonValue"/>
+        </row>
+      </rows>
+    </grid>
+    <hbox>
+      <button id="MoreFewerButton" oncommand="onMoreFewer();" persist="more"/>
+    </hbox>
+    <grid id="MoreSection"><columns><column/><column/></columns>
+      <rows>
+        <row>
+          <spacer/>
+          <checkbox id="ButtonDisabled" label="&ButtonDisabled.label;" accesskey="&ButtonDisabled.accesskey;"/>
+        </row>
+        <row align="center">
+          <label control="ButtonTabIndex" value="&tabIndex.label;" accesskey="&tabIndex.accesskey;"/>
+          <hbox>
+            <textbox id="ButtonTabIndex" class="narrow" oninput="forceInteger(this.id);"/>
+          </hbox>
+        </row>
+        <row align="center">
+          <label control="ButtonAccessKey" value="&AccessKey.label;" accesskey="&AccessKey.accesskey;"/>
+          <hbox>
+            <textbox id="ButtonAccessKey" class="narrow"/>
+          </hbox>
+        </row>
+      </rows>
+    </grid>
+  </groupbox>
+
+  <!-- from EdDialogOverlay -->
+  <hbox flex="1" style="margin-top: 0.2em">
+    <button id="RemoveButton" label="&RemoveButton.label;" accesskey="&RemoveButton.accesskey;" oncommand="RemoveButton();"/>
+    <!-- This will right-align the button -->
+    <spacer flex="1"/>
+    <button id="AdvancedEditButton"/>
+  </hbox>
+  <separator class="groove"/>
+
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdColorPicker.js
@@ -0,0 +1,341 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Daniel Glazman (glazman@netscape.com)
+ *   Charles Manske (cmanske@netscape.com)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+
+//Cancel() is in EdDialogCommon.js
+var insertNew = true;
+var tagname = "TAG NAME"
+var gColor = "";
+var LastPickedColor = "";
+var ColorType = "Text";
+var TextType = false;
+var HighlightType = false;
+var TableOrCell = false;
+var LastPickedIsDefault = true;
+var NoDefault = false;
+var gColorObj;
+
+// dialog initialization code
+function Startup()
+{ 
+  if (!window.arguments[1])
+  {
+    dump("EdColorPicker: Missing color object param\n");
+    return;
+  }
+
+  // window.arguments[1] is object to get initial values and return color data
+  gColorObj = window.arguments[1];
+  gColorObj.Cancel = false;
+
+  gDialog.ColorPicker      = document.getElementById("ColorPicker");
+  gDialog.ColorInput       = document.getElementById("ColorInput");
+  gDialog.LastPickedButton = document.getElementById("LastPickedButton");
+  gDialog.LastPickedColor  = document.getElementById("LastPickedColor");
+  gDialog.CellOrTableGroup = document.getElementById("CellOrTableGroup");
+  gDialog.TableRadio       = document.getElementById("TableRadio");
+  gDialog.CellRadio        = document.getElementById("CellRadio");
+  gDialog.ColorSwatch      = document.getElementById("ColorPickerSwatch");
+  gDialog.Ok               = document.documentElement.getButton("accept");
+
+  // The type of color we are setting: 
+  //  text: Text, Link, ActiveLink, VisitedLink, 
+  //  or background: Page, Table, or Cell
+  if (gColorObj.Type)
+  {
+    ColorType = gColorObj.Type;
+    // Get string for dialog title from passed-in type 
+    //   (note constraint on editor.properties string name)
+    var prefs = GetPrefs();
+    var IsCSSPrefChecked = prefs.getBoolPref("editor.use_css");
+
+    if (GetCurrentEditor())
+    {
+      if (ColorType == "Page" && IsCSSPrefChecked && IsHTMLEditor())
+        document.title = GetString("BlockColor");
+      else
+        document.title = GetString(ColorType + "Color");
+    }
+  }
+
+  gDialog.ColorInput.value = "";
+  var tmpColor;
+  var haveTableRadio = false;
+
+  switch (ColorType)
+  {
+    case "Page":
+      tmpColor = gColorObj.PageColor;
+      if (tmpColor && tmpColor.toLowerCase() != "window")
+        gColor = tmpColor;
+      break;
+    case "Table":
+      if (gColorObj.TableColor)
+        gColor = gColorObj.TableColor;
+      break;
+    case "Cell":
+      if (gColorObj.CellColor)
+        gColor = gColorObj.CellColor;
+      break;
+    case "TableOrCell":
+      TableOrCell = true;
+      document.getElementById("TableOrCellGroup").collapsed = false;
+      haveTableRadio = true;
+      if (gColorObj.SelectedType == "Cell")
+      {
+        gColor = gColorObj.CellColor;
+        gDialog.CellOrTableGroup.selectedItem = gDialog.CellRadio;
+        gDialog.CellRadio.focus();
+      }
+      else
+      {
+        gColor = gColorObj.TableColor;
+        gDialog.CellOrTableGroup.selectedItem = gDialog.TableRadio;
+        gDialog.TableRadio.focus();
+      }
+      break;
+    case "Highlight":
+      HighlightType = true;
+      if (gColorObj.HighlightColor)
+        gColor = gColorObj.HighlightColor;
+      break;
+    default:
+      // Any other type will change some kind of text,
+      TextType = true;
+      tmpColor = gColorObj.TextColor;
+      if (tmpColor && tmpColor.toLowerCase() != "windowtext")
+        gColor = gColorObj.TextColor;
+      break;
+  }
+
+  // Set initial color in input field and in the colorpicker
+  SetCurrentColor(gColor);
+  gDialog.ColorPicker.initColor(gColor);
+
+  // Use last-picked colors passed in, or those persistent on dialog
+  if (TextType)
+  {
+    if ( !("LastTextColor" in gColorObj) || !gColorObj.LastTextColor)
+      gColorObj.LastTextColor = gDialog.LastPickedColor.getAttribute("LastTextColor");
+    LastPickedColor = gColorObj.LastTextColor;
+  }
+  else if (HighlightType)
+  {
+    if ( !("LastHighlightColor" in gColorObj) || !gColorObj.LastHighlightColor)
+      gColorObj.LastHighlightColor = gDialog.LastPickedColor.getAttribute("LastHighlightColor");
+    LastPickedColor = gColorObj.LastHighlightColor;
+  }
+  else
+  {
+    if ( !("LastBackgroundColor" in gColorObj) || !gColorObj.LastBackgroundColor)
+      gColorObj.LastBackgroundColor = gDialog.LastPickedColor.getAttribute("LastBackgroundColor");
+    LastPickedColor = gColorObj.LastBackgroundColor;
+  }
+
+  // Set method to detect clicking on OK button
+  //  so we don't get fooled by changing "default" behavior
+  gDialog.Ok.setAttribute("onclick", "SetDefaultToOk()");
+
+  if (!LastPickedColor) {
+    // Hide the button, as there is no last color available.
+    gDialog.LastPickedButton.hidden = true;
+  } else {
+    gDialog.LastPickedColor.setAttribute("style", "background-color: " + LastPickedColor);
+
+    // Make "Last-picked" the default button, until the user selects a color.
+    gDialog.Ok.removeAttribute("default");
+    gDialog.LastPickedButton.setAttribute("default", "true");
+  }
+
+  // Caller can prevent user from submitting an empty, i.e., default color
+  NoDefault = gColorObj.NoDefault;
+  if (NoDefault)
+  {
+    // Hide the "Default button -- user must pick a color
+    document.getElementById("DefaultColorButton").collapsed = true;
+  }
+
+  // Set focus to colorpicker if not set to table radio buttons above
+  if (!haveTableRadio)
+    gDialog.ColorPicker.focus();
+
+  SetWindowLocation();
+}
+
+function ChangePalette(palette)
+{
+  gDialog.ColorPicker.setAttribute("palettename", palette);
+  window.sizeToContent();
+}
+
+function SelectColor()
+{
+  var color = gDialog.ColorPicker.color;
+  if (color)
+    SetCurrentColor(color);
+}
+
+function RemoveColor()
+{
+  SetCurrentColor("");
+  gDialog.ColorInput.focus();
+  SetDefaultToOk();
+}
+
+function SelectColorByKeypress(aEvent)
+{
+  if (aEvent.charCode == aEvent.DOM_VK_SPACE)
+  {
+    SelectColor();
+    SetDefaultToOk();
+  }
+}
+
+function SelectLastPickedColor()
+{
+  SetCurrentColor(LastPickedColor);
+  if ( onAccept() )
+    //window.close();
+    return true;
+
+  return false;
+}
+
+function SetCurrentColor(color)
+{
+  // TODO: Validate color?
+  if(!color) color = "";
+  gColor = TrimString(color).toLowerCase();
+  if (gColor == "mixed")
+    gColor = "";
+  gDialog.ColorInput.value = gColor;
+  SetColorSwatch();
+}
+
+function SetColorSwatch()
+{
+  // TODO: DON'T ALLOW SPACES?
+  var color = TrimString(gDialog.ColorInput.value);
+  if (color)
+  {
+    gDialog.ColorSwatch.setAttribute("style",("background-color:"+color));
+    gDialog.ColorSwatch.removeAttribute("default");
+  }
+  else
+  {
+    gDialog.ColorSwatch.setAttribute("style",("background-color:inherit"));
+    gDialog.ColorSwatch.setAttribute("default","true");
+  }
+}
+
+function SetDefaultToOk()
+{
+  gDialog.LastPickedButton.removeAttribute("default");
+  gDialog.Ok.setAttribute("default","true");
+  LastPickedIsDefault = false;
+}
+
+function ValidateData()
+{
+  if (LastPickedIsDefault)
+    gColor = LastPickedColor;
+  else
+    gColor = gDialog.ColorInput.value;
+  
+  gColor = TrimString(gColor).toLowerCase();
+
+  // TODO: Validate the color string!
+
+  if (NoDefault && !gColor)
+  {
+    ShowInputErrorMessage(GetString("NoColorError"));
+    SetTextboxFocus(gDialog.ColorInput);
+    return false;   
+  }
+  return true;
+}
+
+function onAccept()
+{
+  if (!ValidateData())
+    return false;
+
+  // Set return values and save in persistent color attributes
+  if (TextType)
+  {
+    gColorObj.TextColor = gColor;
+    if (gColor.length > 0)
+    {
+      gDialog.LastPickedColor.setAttribute("LastTextColor", gColor);
+      gColorObj.LastTextColor = gColor;
+    }
+  }
+  else if (HighlightType)
+  {
+    gColorObj.HighlightColor = gColor;
+    if (gColor.length > 0)
+    {
+      gDialog.LastPickedColor.setAttribute("LastHighlightColor", gColor);
+      gColorObj.LastHighlightColor = gColor;
+    }
+  }
+  else
+  {
+    gColorObj.BackgroundColor = gColor;
+    if (gColor.length > 0)
+    {
+      gDialog.LastPickedColor.setAttribute("LastBackgroundColor", gColor);
+      gColorObj.LastBackgroundColor = gColor;
+    }
+    // If table or cell requested, tell caller which element to set on
+    if (TableOrCell && gDialog.TableRadio.selected)
+      gColorObj.Type = "Table";
+  }
+  SaveWindowLocation();
+
+  return true; // do close the window
+}
+
+function onCancelColor()
+{
+  // Tells caller that user canceled
+  gColorObj.Cancel = true;
+  SaveWindowLocation();
+  return true;
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdColorPicker.xul
@@ -0,0 +1,100 @@
+<?xml version="1.0"?>
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?> 
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EdColorPicker.dtd">
+
+<dialog title="&windowTitle.label;"
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    onload="Startup()"
+    ondialogaccept="return onAccept();"
+    ondialogcancel="return onCancelColor();">
+
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdColorPicker.js"/>
+
+  <broadcaster id="args" value=""/>
+  <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+  <hbox id="TableOrCellGroup" align="center" collapsed="true">
+    <label control="CellOrTableGroup" value="&background.label;" accesskey="&background.accessKey;"/>
+    <radiogroup id="CellOrTableGroup" orient="horizontal">
+      <radio id="TableRadio" label="&table.label;" accesskey="&table.accessKey;"/>
+      <radio id="CellRadio"  label="&cell.label;"  accesskey="&cell.accessKey;"/>
+  </radiogroup>
+  </hbox>
+  <colorpicker id="ColorPicker" palettename="standard" 
+    persist="palettename"
+    onclick="SetDefaultToOk();"
+    ondblclick="if (onAccept()) window.close();"
+    onkeypress="SelectColorByKeypress(event);"
+    onselect="SelectColor();"/>
+<!-- Web palette is not implemented???
+  <hbox align="center">
+    <label value="&palette.label;"/>
+    <radio id="StandardPalette" label="&standardPalette.label;" oncommand="ChangePalette('standard')"/>
+    <radio id="WebPalette" label="&webPalette.label;" oncommand="ChangePalette('web')"/>
+  </hbox>
+-->
+  <spacer class="spacer"/>
+  <vbox flex="1">
+    <button id="LastPickedButton" crop="right" oncommand="SelectLastPickedColor();">
+      <spacer id="LastPickedColor"
+                  LastTextColor="" LastBackgroundColor=""
+                  persist="LastTextColor LastBackgroundColor"/>
+      <label value="&lastPickedColor.label;" accesskey="&lastPickedColor.accessKey;" flex="1" style="text-align: center;"/>
+    </button>
+    <label value="&setColor1.label;"/>
+    <label value="&setColor2.label;" accesskey="&setColor2.accessKey;" control="ColorInput"/>
+    <label value="&setColorExample.label;"/>
+    <hbox align="center" flex="1=">
+      <textbox id="ColorInput" style="width: 8em" oninput="SetColorSwatch(); SetDefaultToOk();"/>
+      <spacer flex="1"/>
+      <spacer id="ColorPickerSwatch"/>
+      <spacer flex="1"/>
+      <button id="DefaultColorButton" label="&default.label;" accesskey="&default.accessKey;"
+        style="margin-right:0px;" oncommand="RemoveColor()"/>
+    </hbox>
+  </vbox>
+  <separator class="groove"/>
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdColorProps.js
@@ -0,0 +1,450 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ Behavior notes:
+ Radio buttons select "UseDefaultColors" vs. "UseCustomColors" modes.
+ If any color attribute is set in the body, mode is "Custom Colors",
+  even if 1 or more (but not all) are actually null (= "use default")
+ When in "Custom Colors" mode, all colors will be set on body tag,
+  even if they are just default colors, to assure compatable colors in page.
+ User cannot select "use default" for individual colors
+*/
+
+//Cancel() is in EdDialogCommon.js
+
+var gBodyElement;
+var prefs;
+var gBackgroundImage;
+
+// Initialize in case we can't get them from prefs???
+var defaultTextColor="#000000";
+var defaultLinkColor="#000099";
+var defaultActiveColor="#000099";
+var defaultVisitedColor="#990099";
+var defaultBackgroundColor="#FFFFFF";
+const styleStr =       "style";
+const textStr =        "text";
+const linkStr =        "link";
+const vlinkStr =       "vlink";
+const alinkStr =       "alink";
+const bgcolorStr =     "bgcolor";
+const backgroundStr =  "background";
+const cssColorStr = "color";
+const cssBackgroundColorStr = "background-color";
+const cssBackgroundImageStr = "background-image";
+const colorStyle =     cssColorStr + ": ";
+const backColorStyle = cssBackgroundColorStr + ": ";
+const backImageStyle = "; " + cssBackgroundImageStr + ": url(";
+
+var customTextColor;
+var customLinkColor;
+var customActiveColor;
+var customVisitedColor;
+var customBackgroundColor;
+var previewBGColor;
+var gHaveDocumentUrl = false;
+
+// dialog initialization code
+function Startup()
+{
+  var editor = GetCurrentEditor();
+  if (!editor)
+  {
+    window.close();
+    return;
+  }
+
+  gDialog.ColorPreview = document.getElementById("ColorPreview");
+  gDialog.NormalText = document.getElementById("NormalText");
+  gDialog.LinkText = document.getElementById("LinkText");
+  gDialog.ActiveLinkText = document.getElementById("ActiveLinkText");
+  gDialog.VisitedLinkText = document.getElementById("VisitedLinkText");
+  gDialog.PageColorGroup = document.getElementById("PageColorGroup");
+  gDialog.DefaultColorsRadio = document.getElementById("DefaultColorsRadio");
+  gDialog.CustomColorsRadio = document.getElementById("CustomColorsRadio");
+  gDialog.BackgroundImageInput = document.getElementById("BackgroundImageInput");
+
+  try {
+    gBodyElement = editor.rootElement;
+  } catch (e) {}
+
+  if (!gBodyElement)
+  {
+    dump("Failed to get BODY element!\n");
+    window.close();
+  }
+
+  // Set element we will edit
+  globalElement = gBodyElement.cloneNode(false);
+
+  // Initialize default colors from browser prefs
+  var browserColors = GetDefaultBrowserColors();
+  if (browserColors)
+  {
+    // Use author's browser pref colors passed into dialog
+    defaultTextColor = browserColors.TextColor;
+    defaultLinkColor = browserColors.LinkColor;
+    defaultActiveColor = browserColors.ActiveLinkColor;
+    defaultVisitedColor =  browserColors.VisitedLinkColor;
+    defaultBackgroundColor=  browserColors.BackgroundColor;
+  }
+
+  // We only need to test for this once per dialog load
+  gHaveDocumentUrl = GetDocumentBaseUrl();
+
+  InitDialog();
+
+  gDialog.PageColorGroup.focus();
+
+  SetWindowLocation();
+}
+
+function InitDialog()
+{
+  // Get image from document
+  gBackgroundImage = GetHTMLOrCSSStyleValue(globalElement, backgroundStr, cssBackgroundImageStr);
+  if (/url\((.*)\)/.test( gBackgroundImage ))
+    gBackgroundImage = RegExp.$1;
+
+  gDialog.BackgroundImageInput.value = gBackgroundImage;
+
+  if (gBackgroundImage)
+    gDialog.ColorPreview.setAttribute(styleStr, backImageStyle+gBackgroundImage+");");
+
+  SetRelativeCheckbox();
+
+  customTextColor        = GetHTMLOrCSSStyleValue(globalElement, textStr, cssColorStr);
+  customTextColor        = ConvertRGBColorIntoHEXColor(customTextColor);
+  customLinkColor        = globalElement.getAttribute(linkStr);
+  customActiveColor      = globalElement.getAttribute(alinkStr);
+  customVisitedColor     = globalElement.getAttribute(vlinkStr);
+  customBackgroundColor  = GetHTMLOrCSSStyleValue(globalElement, bgcolorStr, cssBackgroundColorStr);
+  customBackgroundColor  = ConvertRGBColorIntoHEXColor(customBackgroundColor);
+
+  var haveCustomColor = 
+        customTextColor       ||
+        customLinkColor       ||
+        customVisitedColor    ||
+        customActiveColor     ||
+        customBackgroundColor;
+
+  // Set default color explicitly for any that are missing
+  // PROBLEM: We are using "windowtext" and "window" for the Windows OS
+  //   default color values. This works with CSS in preview window,
+  //   but we should NOT use these as values for HTML attributes!
+
+  if (!customTextColor) customTextColor = defaultTextColor;
+  if (!customLinkColor) customLinkColor = defaultLinkColor;
+  if (!customActiveColor) customActiveColor = defaultActiveColor;
+  if (!customVisitedColor) customVisitedColor = defaultVisitedColor;
+  if (!customBackgroundColor) customBackgroundColor = defaultBackgroundColor;
+
+  if (haveCustomColor)
+  {
+    // If any colors are set, then check the "Custom" radio button
+    gDialog.PageColorGroup.selectedItem = gDialog.CustomColorsRadio;
+    UseCustomColors();
+  }
+  else 
+  {
+    gDialog.PageColorGroup.selectedItem = gDialog.DefaultColorsRadio;
+    UseDefaultColors();
+  }
+}
+
+function GetColorAndUpdate(ColorWellID)
+{
+  // Only allow selecting when in custom mode
+  if (!gDialog.CustomColorsRadio.selected) return;
+
+  var colorWell = document.getElementById(ColorWellID);
+  if (!colorWell) return;
+
+  // Don't allow a blank color, i.e., using the "default"
+  var colorObj = { NoDefault:true, Type:"", TextColor:0, PageColor:0, Cancel:false };
+
+  switch( ColorWellID )
+  {
+    case "textCW":
+      colorObj.Type = "Text";
+      colorObj.TextColor = customTextColor;
+      break;
+    case "linkCW":
+      colorObj.Type = "Link";
+      colorObj.TextColor = customLinkColor;
+      break;
+    case "activeCW":
+      colorObj.Type = "ActiveLink";
+      colorObj.TextColor = customActiveColor;
+      break;
+    case "visitedCW":
+      colorObj.Type = "VisitedLink";
+      colorObj.TextColor = customVisitedColor;
+      break;
+    case "backgroundCW":
+      colorObj.Type = "Page";
+      colorObj.PageColor = customBackgroundColor;
+      break;
+  }
+
+  window.openDialog("chrome://editor/content/EdColorPicker.xul", "_blank", "chrome,close,titlebar,modal", "", colorObj);
+
+  // User canceled the dialog
+  if (colorObj.Cancel)
+    return;
+
+  var color = "";
+  switch( ColorWellID )
+  {
+    case "textCW":
+      color = customTextColor = colorObj.TextColor;
+      break;
+    case "linkCW":
+      color = customLinkColor = colorObj.TextColor;
+      break;
+    case "activeCW":
+      color = customActiveColor = colorObj.TextColor;
+      break;
+    case "visitedCW":
+      color = customVisitedColor = colorObj.TextColor;
+      break;
+    case "backgroundCW":
+      color = customBackgroundColor = colorObj.BackgroundColor;
+      break;
+  }
+
+  setColorWell(ColorWellID, color); 
+  SetColorPreview(ColorWellID, color);
+}
+
+function SetColorPreview(ColorWellID, color)
+{
+  switch( ColorWellID )
+  {
+    case "textCW":
+      gDialog.NormalText.setAttribute(styleStr,colorStyle+color);
+      break;
+    case "linkCW":
+      gDialog.LinkText.setAttribute(styleStr,colorStyle+color);
+      break;
+    case "activeCW":
+      gDialog.ActiveLinkText.setAttribute(styleStr,colorStyle+color);
+      break;
+    case "visitedCW":
+      gDialog.VisitedLinkText.setAttribute(styleStr,colorStyle+color);
+      break;
+    case "backgroundCW":
+      // Must combine background color and image style values
+      var styleValue = backColorStyle+color;
+      if (gBackgroundImage)
+        styleValue += ";"+backImageStyle+gBackgroundImage+");";
+
+      gDialog.ColorPreview.setAttribute(styleStr,styleValue);
+      previewBGColor = color;
+      break;
+  }
+}
+
+function UseCustomColors()
+{
+  SetElementEnabledById("TextButton", true);
+  SetElementEnabledById("LinkButton", true);
+  SetElementEnabledById("ActiveLinkButton", true);
+  SetElementEnabledById("VisitedLinkButton", true);
+  SetElementEnabledById("BackgroundButton", true);
+  SetElementEnabledById("Text", true);
+  SetElementEnabledById("Link", true);
+  SetElementEnabledById("Active", true);
+  SetElementEnabledById("Visited", true);
+  SetElementEnabledById("Background", true);
+
+  SetColorPreview("textCW",       customTextColor);
+  SetColorPreview("linkCW",       customLinkColor);
+  SetColorPreview("activeCW",     customActiveColor);
+  SetColorPreview("visitedCW",    customVisitedColor);
+  SetColorPreview("backgroundCW", customBackgroundColor);
+
+  setColorWell("textCW",          customTextColor);
+  setColorWell("linkCW",          customLinkColor);
+  setColorWell("activeCW",        customActiveColor);
+  setColorWell("visitedCW",       customVisitedColor);
+  setColorWell("backgroundCW",    customBackgroundColor);
+}
+
+function UseDefaultColors()
+{
+  SetColorPreview("textCW",       defaultTextColor);
+  SetColorPreview("linkCW",       defaultLinkColor);
+  SetColorPreview("activeCW",     defaultActiveColor);
+  SetColorPreview("visitedCW",    defaultVisitedColor);
+  SetColorPreview("backgroundCW", defaultBackgroundColor);
+
+  // Setting to blank color will remove color from buttons,
+  setColorWell("textCW",       "");
+  setColorWell("linkCW",       "");
+  setColorWell("activeCW",     "");
+  setColorWell("visitedCW",    "");
+  setColorWell("backgroundCW", "");
+
+  // Disable color buttons and labels
+  SetElementEnabledById("TextButton", false);
+  SetElementEnabledById("LinkButton", false);
+  SetElementEnabledById("ActiveLinkButton", false);
+  SetElementEnabledById("VisitedLinkButton", false);
+  SetElementEnabledById("BackgroundButton", false);
+  SetElementEnabledById("Text", false);
+  SetElementEnabledById("Link", false);
+  SetElementEnabledById("Active", false);
+  SetElementEnabledById("Visited", false);
+  SetElementEnabledById("Background", false);
+}
+
+function chooseFile()
+{
+  // Get a local image file, converted into URL format
+  var fileName = GetLocalFileURL("img");
+  if (fileName)
+  {
+    // Always try to relativize local file URLs
+    if (gHaveDocumentUrl)
+      fileName = MakeRelativeUrl(fileName);
+
+    gDialog.BackgroundImageInput.value = fileName;
+
+    SetRelativeCheckbox();
+
+    ValidateAndPreviewImage(true);
+  }
+  SetTextboxFocus(gDialog.BackgroundImageInput);
+}
+
+function ChangeBackgroundImage()
+{
+  // Don't show error message for image while user is typing
+  ValidateAndPreviewImage(false);
+  SetRelativeCheckbox();
+}
+
+function ValidateAndPreviewImage(ShowErrorMessage)
+{
+  // First make a string with just background color
+  var styleValue = backColorStyle+previewBGColor+";";
+
+  var retVal = true;
+  var image = TrimString(gDialog.BackgroundImageInput.value);
+  if (image)
+  {
+    gBackgroundImage = image;
+
+    // Display must use absolute URL if possible
+    var displayImage = gHaveDocumentUrl ? MakeAbsoluteUrl(image) : image;
+    styleValue += backImageStyle+displayImage+");";
+  }
+  else gBackgroundImage = null;
+
+  // Set style on preview (removes image if not valid)
+  gDialog.ColorPreview.setAttribute(styleStr, styleValue);
+
+  // Note that an "empty" string is valid
+  return retVal;
+}
+
+function ValidateData()
+{
+  var editor = GetCurrentEditor();
+  try {
+    // Colors values are updated as they are picked, no validation necessary
+    if (gDialog.DefaultColorsRadio.selected)
+    {
+      editor.removeAttributeOrEquivalent(globalElement, textStr, true);
+      globalElement.removeAttribute(linkStr);
+      globalElement.removeAttribute(vlinkStr);
+      globalElement.removeAttribute(alinkStr);
+      editor.removeAttributeOrEquivalent(globalElement, bgcolorStr, true);
+    }
+    else
+    {
+      //Do NOT accept the CSS "WindowsOS" color strings!
+      // Problem: We really should try to get the actual color values
+      //  from windows, but I don't know how to do that!
+      var tmpColor = customTextColor.toLowerCase();
+      if (tmpColor != "windowtext")
+        editor.setAttributeOrEquivalent(globalElement, textStr,
+                                        customTextColor, true);
+      else
+        editor.removeAttributeOrEquivalent(globalElement, textStr, true);
+
+      tmpColor = customBackgroundColor.toLowerCase();
+      if (tmpColor != "window")
+        editor.setAttributeOrEquivalent(globalElement, bgcolorStr, customBackgroundColor, true);
+      else
+        editor.removeAttributeOrEquivalent(globalElement, bgcolorStr, true);
+
+      globalElement.setAttribute(linkStr,    customLinkColor);
+      globalElement.setAttribute(vlinkStr,   customVisitedColor);
+      globalElement.setAttribute(alinkStr,   customActiveColor);
+    }
+
+    if (ValidateAndPreviewImage(true))
+    {
+      // A valid image may be null for no image
+      if (gBackgroundImage)
+        globalElement.setAttribute(backgroundStr, gBackgroundImage);
+      else
+        editor.removeAttributeOrEquivalent(globalElement, backgroundStr, true);
+  
+      return true;
+    }  
+  } catch (e) {}
+  return false;
+}
+
+function onAccept()
+{
+  if (ValidateData())
+  {
+    // Copy attributes to element we are changing
+    try {
+      GetCurrentEditor().cloneAttributes(gBodyElement, globalElement);
+    } catch (e) {}
+
+    SaveWindowLocation();
+    return true; // do close the window
+  }
+  return false;
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdColorProps.xul
@@ -0,0 +1,151 @@
+<?xml version="1.0"?>
+
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?> 
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorColorProperties.dtd">
+
+<dialog title="&windowTitle.label;"
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    onload="Startup()"
+    ondialogaccept="return onAccept();"
+    ondialogcancel="return onCancel();">
+
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdColorProps.js"/>
+
+  <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+  <broadcaster id="args" value=""/>
+
+  <groupbox align="start">
+    <caption label="&pageColors.label;"/>
+    <radiogroup id="PageColorGroup">
+      <radio id="DefaultColorsRadio" label="&defaultColorsRadio.label;" oncommand="UseDefaultColors()"
+        accesskey="&defaultColorsRadio.accessKey;"
+        tooltiptext="&defaultColorsRadio.tooltip;" />
+      <radio id="CustomColorsRadio" label="&customColorsRadio.label;" oncommand="UseCustomColors()"
+        accesskey="&customColorsRadio.accessKey;"
+        tooltiptext="&customColorsRadio.tooltip;" />
+    </radiogroup>
+    <hbox class="indent">
+      <grid>
+        <columns><column/><column/></columns>
+        <rows>
+          <row align="center">
+            <label id="Text" control="TextButton"
+                   value="&normalText.label;&colon.character;"
+                   accesskey="&normalText.accessKey;"/>
+            <button id="TextButton" class="color-button" oncommand="GetColorAndUpdate('textCW');">
+              <spacer id="textCW" class="color-well"/>
+            </button>
+          </row>
+          <row align="center">
+            <label id="Link" control="LinkButton"
+                   value="&linkText.label;&colon.character;"
+                   accesskey="&linkText.accessKey;"/>
+            <button id="LinkButton" class="color-button" oncommand="GetColorAndUpdate('linkCW');">
+              <spacer id="linkCW" class="color-well"/>
+            </button>
+          </row>
+          <row align="center">
+            <label id="Active" control="ActiveLinkButton"
+                   value="&activeLinkText.label;&colon.character;"
+                   accesskey="&activeLinkText.accessKey;"/>
+            <button id="ActiveLinkButton" class="color-button" oncommand="GetColorAndUpdate('activeCW');">
+              <spacer id="activeCW" class="color-well"/>
+            </button>
+          </row>
+          <row align="center">
+            <label id="Visited" control="VisitedLinkButton"
+                   value="&visitedLinkText.label;&colon.character;"
+                   accesskey="&visitedLinkText.accessKey;"/>
+            <button id="VisitedLinkButton" class="color-button" oncommand="GetColorAndUpdate('visitedCW');">
+              <spacer id="visitedCW" class="color-well"/>
+            </button>
+          </row>
+          <row align="center">
+            <label id="Background" control="BackgroundButton"
+                   value="&background.label;"
+                   accesskey="&background.accessKey;"/>
+            <button id="BackgroundButton" class="color-button" oncommand="GetColorAndUpdate('backgroundCW');">
+              <spacer id="backgroundCW" class="color-well"/>
+            </button>
+          </row>
+        </rows>
+      </grid>
+      <vbox id="ColorPreview" flex="1">
+        <spacer flex="1"/>
+        <label class="larger" id="NormalText"      value="&normalText.label;"/>
+        <spacer flex="1"/>
+        <label class="larger" id="LinkText"        value="&linkText.label;"/>
+        <spacer flex="1"/>
+        <label class="larger" id="ActiveLinkText"  value="&activeLinkText.label;"/>
+        <spacer flex="1"/>
+        <label class="larger" id="VisitedLinkText" value="&visitedLinkText.label;"/>
+        <spacer flex="1"/>
+      </vbox>
+      <spacer flex="1"/>
+    </hbox>
+    <spacer class="spacer"/>
+  </groupbox>
+  <spacer class="spacer"/>
+  <label control="BackgroundImageInput"
+         value="&backgroundImage.label;"
+         accesskey="&backgroundImage.accessKey;"/>
+  <textbox id="BackgroundImageInput" class="uri-element" oninput="ChangeBackgroundImage()"
+   tooltiptext="&backgroundImage.tooltip;" flex="1"/>
+  <hbox align="center">
+    <!-- from EdDialogOverlay.xul 'for' identifies the textfield to get URL from -->
+    <checkbox id="MakeRelativeCheckbox" for="BackgroundImageInput"/>
+    <spacer flex="1"/>
+    <!-- from EdDialogOverlay.xul -->
+    <button id="ChooseFile"/>
+  </hbox>
+  <spacer class="smallspacer"/>
+  <hbox>
+    <spacer flex="1"/>
+    <!-- from EdDialogOverlay.xul -->
+    <button id="AdvancedEditButton"/>
+  </hbox>
+  <separator class="groove"/>
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdConvertToTable.js
@@ -0,0 +1,365 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Charles Manske (cmanske@netscape.com)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var gIndex;
+var gCommaIndex = "0";
+var gSpaceIndex = "1";
+var gOtherIndex = "2";
+
+// dialog initialization code
+function Startup()
+{
+  if (!GetCurrentEditor())
+  {
+    window.close();
+    return;
+  }
+
+  gDialog.sepRadioGroup      = document.getElementById("SepRadioGroup");
+  gDialog.sepCharacterInput  = document.getElementById("SepCharacterInput");
+  gDialog.deleteSepCharacter = document.getElementById("DeleteSepCharacter");
+  gDialog.collapseSpaces     = document.getElementById("CollapseSpaces");
+
+  // We persist the user's separator character
+  gDialog.sepCharacterInput.value = gDialog.sepRadioGroup.getAttribute("character");
+
+  gIndex = gDialog.sepRadioGroup.getAttribute("index");
+
+  switch (gIndex)
+  {
+    case gCommaIndex:
+    default:
+      gDialog.sepRadioGroup.selectedItem = document.getElementById("comma");
+      break;
+    case gSpaceIndex:
+      gDialog.sepRadioGroup.selectedItem = document.getElementById("space");
+      break;
+    case gOtherIndex:
+      gDialog.sepRadioGroup.selectedItem = document.getElementById("other");
+      break;
+  }
+
+  // Set initial enable state on character input and "collapse" checkbox
+  SelectCharacter(gIndex);
+
+  SetWindowLocation();
+}
+
+function InputSepCharacter()
+{
+  var str = gDialog.sepCharacterInput.value;
+
+  // Limit input to 1 character
+  if (str.length > 1)
+    str = str.slice(0,1);
+
+  // We can never allow tag or entity delimiters for separator character
+  if (str == "<" || str == ">" || str == "&" || str == ";" || str == " ")
+    str = "";
+
+  gDialog.sepCharacterInput.value = str;
+}
+
+function SelectCharacter(radioGroupIndex)
+{
+  gIndex = radioGroupIndex;
+  SetElementEnabledById("SepCharacterInput", gIndex == gOtherIndex);
+  SetElementEnabledById("CollapseSpaces", gIndex == gSpaceIndex);
+}
+
+function onAccept()
+{
+  var sepCharacter = "";
+  switch ( gIndex )
+  {
+    case gCommaIndex:
+      sepCharacter = ",";
+      break;
+    case gSpaceIndex:
+      sepCharacter = " ";
+      break;
+    case gOtherIndex:
+      sepCharacter = gDialog.sepCharacterInput.value.slice(0,1);
+      break;
+  }
+
+  var editor = GetCurrentEditor();
+  var str;
+  try {
+    str = editor.outputToString("text/html", kOutputLFLineBreak | kOutputSelectionOnly);
+  } catch (e) {}
+  if (!str)
+  {
+    SaveWindowLocation();
+    return true;
+  }
+
+  // Replace nbsp with spaces:
+  str = str.replace(/\u00a0/g, " ");
+
+  // Strip out </p> completely
+  str = str.replace(/\s*<\/p>\s*/g, "");
+
+  // Trim whitespace adjacent to <p> and <br> tags
+  //  and replace <p> with <br> 
+  //  (which will be replaced with </tr> below)
+  str = str.replace(/\s*<p>\s*|\s*<br>\s*/g, "<br>");
+
+  // Trim leading <br>s
+  str = str.replace(/^(<br>)+/, "");
+
+  // Trim trailing <br>s
+  str = str.replace(/(<br>)+$/, "");
+
+  // Reduce multiple internal <br> to just 1
+  // TODO: Maybe add a checkbox to let user decide
+  //str = str.replace(/(<br>)+/g, "<br>");
+
+  // Trim leading and trailing spaces
+  str = str.replace(/^\s+|\s+$/, "");
+
+  // Remove all tag contents so we don't replace
+  //   separator character within tags
+  // Also converts lists to something usefull
+  var stack = [];
+  var start;
+  var end;
+  var searchStart = 0;
+  var listSeparator = "";
+  var listItemSeparator = "";
+  var endList = false;
+
+  do {
+    start = str.indexOf("<", searchStart);
+
+    if (start >= 0)
+    {
+      end = str.indexOf(">", start+1);
+      if (end > start)
+      {
+        var tagContent = TrimString(str.slice(start+1, end));
+
+        if ( /^ol|^ul|^dl/.test(tagContent) )
+        {
+          //  Replace list tag with <BR> to start new row 
+          //   at begining of second or greater list tag
+          str = str.slice(0, start) + listSeparator + str.slice(end+1);
+          if (listSeparator == "")
+            listSeparator = "<br>";
+          
+          // Reset for list item separation into cells
+          listItemSeparator = "";
+        }
+        else if ( /^li|^dt|^dd/.test(tagContent) )
+        {
+          // Start a new row if this is first item after the ending the last list
+          if (endList)
+            listItemSeparator = "<br>";
+
+          // Start new cell at begining of second or greater list items
+          str = str.slice(0, start) + listItemSeparator + str.slice(end+1);
+
+          if (endList || listItemSeparator == "")
+            listItemSeparator = sepCharacter;
+
+          endList = false;
+        }
+        else 
+        {
+          // Find end tags
+          endList = /^\/ol|^\/ul|^\/dl/.test(tagContent);
+          if ( endList || /^\/li|^\/dt|^\/dd/.test(tagContent) )
+          {
+            // Strip out tag
+            str = str.slice(0, start) + str.slice(end+1);
+          }
+          else
+          {
+            // Not a list-related tag: Store tag contents in an array
+            stack.push(tagContent);
+           
+            // Keep the "<" and ">" while removing from source string
+            start++;
+            str = str.slice(0, start) + str.slice(end);
+          }
+        }
+      }
+      searchStart = start + 1;
+    }
+  } while (start >= 0);
+
+  // Replace separator characters with table cells
+  var replaceString;
+  if (gDialog.deleteSepCharacter.checked)
+  {
+    replaceString = "";
+  }  
+  else
+  {
+    // Don't delete separator character,
+    //  so include it at start of string to replace
+    replaceString = sepCharacter;
+  }
+
+  replaceString += "<td>"; 
+
+  if (sepCharacter.length > 0)
+  {
+    var tempStr = sepCharacter;
+    var regExpChars = ".!@#$%^&*-+[]{}()\|\\\/";
+    if (regExpChars.indexOf(sepCharacter) >= 0)
+      tempStr = "\\" + sepCharacter;
+
+    if (gIndex == gSpaceIndex)
+    {
+      // If checkbox is checked, 
+      //   one or more adjacent spaces are one separator
+      if (gDialog.collapseSpaces.checked)
+          tempStr = "\\s+"
+        else
+          tempStr = "\\s";
+    }
+    var pattern = new RegExp(tempStr, "g");
+    str = str.replace(pattern, replaceString);
+  }
+
+  // Put back tag contents that we removed above
+  searchStart = 0;
+  var stackIndex = 0;
+  do {
+    start = str.indexOf("<", searchStart);
+    end = start + 1;
+    if (start >= 0 && str.charAt(end) == ">")
+    {
+      // We really need a FIFO stack!
+      str = str.slice(0, end) + stack[stackIndex++] + str.slice(end);
+    }
+    searchStart = end;
+
+  } while (start >= 0);
+
+  // End table row and start another for each br or p
+  str = str.replace(/\s*<br>\s*/g, "</tr>\n<tr><td>");
+
+  // Add the table tags and the opening and closing tr/td tags
+  // Default table attributes should be same as those used in nsHTMLEditor::CreateElementWithDefaults()
+  // (Default width="100%" is used in EdInsertTable.js)
+  str = "<table border=\"1\" width=\"100%\" cellpadding=\"2\" cellspacing=\"2\">\n<tr><td>" + str + "</tr>\n</table>\n";
+
+  editor.beginTransaction();
+  
+  // Delete the selection -- makes it easier to find where table will insert
+  var nodeBeforeTable = null;
+  var nodeAfterTable = null;
+  try {
+    editor.deleteSelection(0);
+
+    var anchorNodeBeforeInsert = editor.selection.anchorNode;
+    var offset = editor.selection.anchorOffset;
+    if (anchorNodeBeforeInsert.nodeType == Node.TEXT_NODE)
+    {
+      // Text was split. Table should be right after the first or before 
+      nodeBeforeTable = anchorNodeBeforeInsert.previousSibling;
+      nodeAfterTable = anchorNodeBeforeInsert;
+    }
+    else
+    {
+      // Table should be inserted right after node pointed to by selection
+      if (offset > 0)
+        nodeBeforeTable = anchorNodeBeforeInsert.childNodes.item(offset - 1);
+
+      nodeAfterTable = anchorNodeBeforeInsert.childNodes.item(offset);
+    }
+  
+    editor.insertHTML(str);
+  } catch (e) {}
+
+  var table = null;
+  if (nodeAfterTable)
+  {
+    var previous = nodeAfterTable.previousSibling;
+    if (previous && previous.nodeName.toLowerCase() == "table")
+      table = previous;
+  }
+  if (!table && nodeBeforeTable)
+  {
+    var next = nodeBeforeTable.nextSibling;
+    if (next && next.nodeName.toLowerCase() == "table")
+      table = next;
+  }
+
+  if (table)
+  {
+    // Fixup table only if pref is set
+    var prefs = GetPrefs();
+    var firstRow;
+    try {
+      if (prefs && prefs.getBoolPref("editor.table.maintain_structure") )
+        editor.normalizeTable(table);
+
+      firstRow = editor.getFirstRow(table);
+    } catch(e) {}
+
+    // Put caret in first cell
+    if (firstRow)
+    {
+      var node2 = firstRow.firstChild;
+      do {
+        if (node2.nodeName.toLowerCase() == "td" ||
+            node2.nodeName.toLowerCase() == "th")
+        {
+          try { 
+            editor.selection.collapse(node2, 0);
+          } catch(e) {}
+          break;
+        }
+        node2 = node.nextSibling;
+      } while (node2);
+    }
+  }
+
+  editor.endTransaction();
+
+  // Save persisted attributes
+  gDialog.sepRadioGroup.setAttribute("index", gIndex);
+  if (gIndex == gOtherIndex)
+    gDialog.sepRadioGroup.setAttribute("character", sepCharacter);
+
+  SaveWindowLocation();
+  return true;
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdConvertToTable.xul
@@ -0,0 +1,80 @@
+<?xml version="1.0"?>
+
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?> 
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EdConvertToTable.dtd">
+
+<dialog title="&windowTitle.label;"
+   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+   onload = "Startup()"
+   ondialogaccept="return onAccept();"
+   ondialogcancel="return onCancel();"
+   style="min-width:20em">
+
+  <!-- Methods common to all editor dialogs -->
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <!--- Element-specific methods -->
+  <script type="application/x-javascript" src="chrome://editor/content/EdConvertToTable.js"/>
+
+  <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+  <description class="wrap" flex="1">&instructions1.label;</description>
+  <description class="wrap" flex="1">&instructions2.label;</description>
+  <radiogroup id="SepRadioGroup" persist="index character" index="0" character="">
+    <radio id="comma" label="&commaRadio.label;" oncommand="SelectCharacter('0');"/>
+    <radio id="space" label="&spaceRadio.label;" oncommand="SelectCharacter('1');"/>
+    <hbox>
+      <spacer class="radio-spacer"/>
+      <checkbox id="CollapseSpaces" label="&collapseSpaces.label;"
+                checked="true" persist="checked"
+                tooltiptext="&collapseSpaces.tooltip;"/>
+    </hbox>
+    <hbox align="center">
+      <radio id="other" label="&otherRadio.label;" oncommand="SelectCharacter('2');"/>
+      <textbox class="narrow" id="SepCharacterInput" oninput="InputSepCharacter()"/>
+    </hbox>
+  </radiogroup> 
+  <spacer class="spacer"/>
+  <checkbox id="DeleteSepCharacter" label="&deleteCharCheck.label;" persist="checked"/>
+  <separator class="groove"/>
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdDialogCommon.js
@@ -0,0 +1,1090 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Pete Collins
+ *   Brian King
+ *   Charles Manske (cmanske@netscape.com)
+ *   Neil Rashbrook (neil@parkwaycc.co.uk)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// Each editor window must include this file
+
+// Object to attach commonly-used widgets (all dialogs should use this)
+var gDialog = {};
+
+var gValidationError = false;
+
+// Use for 'defaultIndex' param in InitPixelOrPercentMenulist
+const gPixel = 0;
+const gPercent = 1;
+
+const gMaxPixels  = 100000; // Used for image size, borders, spacing, and padding
+// Gecko code uses 1000 for maximum rowspan, colspan
+// Also, editing performance is really bad above this
+const gMaxRows    = 1000;
+const gMaxColumns = 1000;
+const gMaxTableSize = 1000000; // Width or height of table or cells
+
+// For dialogs that expand in size. Default is smaller size see "onMoreFewer()" below
+var SeeMore = false;
+
+// A XUL element with id="location" for managing
+// dialog location relative to parent window
+var gLocation;
+
+// The element being edited - so AdvancedEdit can have access to it
+var globalElement;
+
+/* Validate contents of an input field 
+ *
+ *  inputWidget    The 'textbox' XUL element for text input of the attribute's value
+ *  listWidget     The 'menulist' XUL element for choosing "pixel" or "percent"
+ *                  May be null when no pixel/percent is used.
+ *  minVal         minimum allowed for input widget's value
+ *  maxVal         maximum allowed for input widget's value
+ *                 (when "listWidget" is used, maxVal is used for "pixel" maximum,
+ *                  100% is assumed if "percent" is the user's choice)
+ *  element        The DOM element that we set the attribute on. May be null.
+ *  attName        Name of the attribute to set.  May be null or ignored if "element" is null
+ *  mustHaveValue  If true, error dialog is displayed if "value" is empty string
+ *
+ *  This calls "ValidateNumberRange()", which puts up an error dialog to inform the user. 
+ *    If error, we also: 
+ *      Shift focus and select contents of the inputWidget,
+ *      Switch to appropriate panel of tabbed dialog if user implements "SwitchToValidate()",
+ *      and/or will expand the dialog to full size if "More / Fewer" feature is implemented
+ *
+ *  Returns the "value" as a string, or "" if error or input contents are empty
+ *  The global "gValidationError" variable is set true if error was found
+ */
+function ValidateNumber(inputWidget, listWidget, minVal, maxVal, element, attName, mustHaveValue, mustShowMoreSection)
+{
+  if (!inputWidget)
+  {
+    gValidationError = true;
+    return "";
+  }
+
+  // Global error return value
+  gValidationError = false;
+  var maxLimit = maxVal;
+  var isPercent = false;
+
+  var numString = TrimString(inputWidget.value);
+  if (numString || mustHaveValue)
+  {
+    if (listWidget)
+      isPercent = (listWidget.selectedIndex == 1);
+    if (isPercent)
+      maxLimit = 100;
+
+    // This method puts up the error message
+    numString = ValidateNumberRange(numString, minVal, maxLimit, mustHaveValue);
+    if(!numString)
+    {
+      // Switch to appropriate panel for error reporting
+      SwitchToValidatePanel();
+
+      // or expand dialog for users of "More / Fewer" button
+      if ("dialog" in window && dialog && 
+           "MoreSection" in gDialog && gDialog.MoreSection)
+      {
+        if ( !SeeMore )
+          onMoreFewer();
+      }
+
+      // Error - shift to offending input widget
+      SetTextboxFocus(inputWidget);
+      gValidationError = true;
+    }
+    else
+    {
+      if (isPercent)
+        numString += "%";
+      if (element)
+        GetCurrentEditor().setAttributeOrEquivalent(element, attName, numString, true);
+    }
+  } else if (element) {
+    GetCurrentEditor().removeAttributeOrEquivalent(element, attName, true)
+  }
+  return numString;
+}
+
+/* Validate contents of an input field 
+ *
+ *  value          number to validate
+ *  minVal         minimum allowed for input widget's value
+ *  maxVal         maximum allowed for input widget's value
+ *                 (when "listWidget" is used, maxVal is used for "pixel" maximum,
+ *                  100% is assumed if "percent" is the user's choice)
+ *  mustHaveValue  If true, error dialog is displayed if "value" is empty string
+ *
+ *  If inputWidget's value is outside of range, or is empty when "mustHaveValue" = true,
+ *      an error dialog is popuped up to inform the user. The focus is shifted
+ *      to the inputWidget.
+ *
+ *  Returns the "value" as a string, or "" if error or input contents are empty
+ *  The global "gValidationError" variable is set true if error was found
+ */
+function ValidateNumberRange(value, minValue, maxValue, mustHaveValue)
+{
+  // Initialize global error flag
+  gValidationError = false;
+  value = TrimString(String(value));
+
+  // We don't show error for empty string unless caller wants to
+  if (!value && !mustHaveValue)
+    return "";
+
+  var numberStr = "";
+
+  if (value.length > 0)
+  {
+    // Extract just numeric characters
+    var number = Number(value.replace(/\D+/g, ""));
+    if (number >= minValue && number <= maxValue )
+    {
+      // Return string version of the number
+      return String(number);
+    }
+    numberStr = String(number);
+  }
+
+  var message = "";
+
+  if (numberStr.length > 0)
+  {
+    // We have a number from user outside of allowed range
+    message = GetString( "ValidateRangeMsg");
+    message = message.replace(/%n%/, numberStr);
+    message += "\n ";
+  }
+  message += GetString( "ValidateNumberMsg");
+
+  // Replace variable placeholders in message with number values
+  message = message.replace(/%min%/, minValue).replace(/%max%/, maxValue);
+  ShowInputErrorMessage(message);
+
+  // Return an empty string to indicate error
+  gValidationError = true;
+  return "";
+}
+
+function SetTextboxFocusById(id)
+{
+  SetTextboxFocus(document.getElementById(id));
+}
+
+function SetTextboxFocus(textbox)
+{
+  if (textbox)
+  {
+    //XXX Using the setTimeout is hacky workaround for bug 103197
+    // Must create a new function to keep "textbox" in scope
+    setTimeout( function(textbox) { textbox.focus(); textbox.select(); }, 0, textbox );
+  }
+}
+
+function ShowInputErrorMessage(message)
+{
+  AlertWithTitle(GetString("InputError"), message);
+  window.focus();
+}
+
+// Get the text appropriate to parent container
+//  to determine what a "%" value is referring to.
+// elementForAtt is element we are actually setting attributes on
+//  (a temporary copy of element in the doc to allow canceling),
+//  but elementInDoc is needed to find parent context in document
+function GetAppropriatePercentString(elementForAtt, elementInDoc)
+{
+  var editor = GetCurrentEditor();
+  try {
+    var name = elementForAtt.nodeName.toLowerCase();
+    if ( name == "td" || name == "th")
+      return GetString("PercentOfTable");
+
+    // Check if element is within a table cell
+    if (editor.getElementOrParentByTagName("td", elementInDoc))
+      return GetString("PercentOfCell");
+    else
+      return GetString("PercentOfWindow");
+  } catch (e) { return "";}
+}
+
+function ClearListbox(listbox)
+{
+  if (listbox)
+  {
+    listbox.clearSelection();
+    while (listbox.firstChild)
+      listbox.removeChild(listbox.firstChild);
+  }
+}
+
+function forceInteger(elementID)
+{
+  var editField = document.getElementById( elementID );
+  if ( !editField )
+    return;
+
+  var stringIn = editField.value;
+  if (stringIn && stringIn.length > 0)
+  {
+    // Strip out all nonnumeric characters
+    stringIn = stringIn.replace(/\D+/g,"");
+    if (!stringIn) stringIn = "";
+
+    // Write back only if changed
+    if (stringIn != editField.value)
+      editField.value = stringIn;
+  }
+}
+
+function InitPixelOrPercentMenulist(elementForAtt, elementInDoc, attribute, menulistID, defaultIndex)
+{
+  if (!defaultIndex) defaultIndex = gPixel;
+
+  // var size  = elementForAtt.getAttribute(attribute);
+  var size = GetHTMLOrCSSStyleValue(elementForAtt, attribute, attribute)
+  var menulist = document.getElementById(menulistID);
+  var pixelItem;
+  var percentItem;
+
+  if (!menulist)
+  {
+    dump("NO MENULIST found for ID="+menulistID+"\n");
+    return size;
+  }
+
+  menulist.removeAllItems();
+  pixelItem = menulist.appendItem(GetString("Pixels"));
+
+  if (!pixelItem) return 0;
+
+  percentItem = menulist.appendItem(GetAppropriatePercentString(elementForAtt, elementInDoc));
+  if (size && size.length > 0)
+  {
+    // Search for a "%" or "px"
+    if (/%/.test(size))
+    {
+      // Strip out the %
+      size = RegExp.leftContext;
+      if (percentItem)
+        menulist.selectedItem = percentItem;
+    }
+    else
+    {
+      if (/px/.test(size))
+        // Strip out the px
+        size = RegExp.leftContext;
+      menulist.selectedItem = pixelItem;
+    }
+  }
+  else
+    menulist.selectedIndex = defaultIndex;
+
+  return size;
+}
+
+function onAdvancedEdit()
+{
+  // First validate data from widgets in the "simpler" property dialog
+  if (ValidateData())
+  {
+    // Set true if OK is clicked in the Advanced Edit dialog
+    window.AdvancedEditOK = false;
+    // Open the AdvancedEdit dialog, passing in the element to be edited
+    //  (the copy named "globalElement")
+    window.openDialog("chrome://editor/content/EdAdvancedEdit.xul", "_blank", "chrome,close,titlebar,modal,resizable=yes", "", globalElement);
+    window.focus();
+    if (window.AdvancedEditOK)
+    {
+      // Copy edited attributes to the dialog widgets:
+      InitDialog();
+    }
+  }
+}
+
+function getColor(ColorPickerID)
+{
+  var colorPicker = document.getElementById(ColorPickerID);
+  var color;
+  if (colorPicker)
+  {
+    // Extract color from colorPicker and assign to colorWell.
+    color = colorPicker.getAttribute("color");
+    if (color && color == "")
+      return null;
+    // Clear color so next if it's called again before
+    //  color picker is actually used, we dedect the "don't set color" state
+    colorPicker.setAttribute("color","");
+  }
+
+  return color;
+}
+
+function setColorWell(ColorWellID, color)
+{
+  var colorWell = document.getElementById(ColorWellID);
+  if (colorWell)
+  {
+    if (!color || color == "")
+    {
+      // Don't set color (use default)
+      // Trigger change to not show color swatch
+      colorWell.setAttribute("default","true");
+      // Style in CSS sets "background-color",
+      //   but color won't clear unless we do this:
+      colorWell.removeAttribute("style");
+    }
+    else
+    {
+      colorWell.removeAttribute("default");
+      // Use setAttribute so colorwell can be a XUL element, such as button
+      colorWell.setAttribute("style", "background-color:"+color);
+    }
+  }
+}
+
+function getColorAndSetColorWell(ColorPickerID, ColorWellID)
+{
+  var color = getColor(ColorPickerID);
+  setColorWell(ColorWellID, color);
+  return color;
+}
+
+function InitMoreFewer()
+{
+  // Set SeeMore bool to the OPPOSITE of the current state,
+  //   which is automatically saved by using the 'persist="more"'
+  //   attribute on the gDialog.MoreFewerButton button
+  //   onMoreFewer will toggle it and redraw the dialog
+  SeeMore = (gDialog.MoreFewerButton.getAttribute("more") != "1");
+  onMoreFewer();
+  gDialog.MoreFewerButton.setAttribute("accesskey",GetString("PropertiesAccessKey"));
+}
+
+function onMoreFewer()
+{
+  if (SeeMore)
+  {
+    gDialog.MoreSection.collapsed = true;
+    gDialog.MoreFewerButton.setAttribute("more","0");
+    gDialog.MoreFewerButton.setAttribute("label",GetString("MoreProperties"));
+    SeeMore = false;
+  }
+  else
+  {
+    gDialog.MoreSection.collapsed = false;
+    gDialog.MoreFewerButton.setAttribute("more","1");
+    gDialog.MoreFewerButton.setAttribute("label",GetString("FewerProperties"));
+    SeeMore = true;
+  }
+  window.sizeToContent();
+}
+
+function SwitchToValidatePanel()
+{
+  // no default implementation
+  // Only EdTableProps.js currently implements this
+}
+
+const nsIFilePicker = Components.interfaces.nsIFilePicker;
+
+function GetLocalFileURL(filterType)
+{
+  var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
+  var fileType = "html";
+
+  if (filterType == "img")
+  {
+    fp.init(window, GetString("SelectImageFile"), nsIFilePicker.modeOpen);
+    fp.appendFilters(nsIFilePicker.filterImages);
+    fileType = "image";
+  }
+  // Current usage of this is in Link dialog,
+  //  where we always want HTML first
+  else if (filterType.indexOf("html") == 0)
+  {
+    fp.init(window, GetString("OpenHTMLFile"), nsIFilePicker.modeOpen);
+
+    // When loading into Composer, direct user to prefer HTML files and text files,
+    //   so we call separately to control the order of the filter list
+    fp.appendFilters(nsIFilePicker.filterHTML);
+    fp.appendFilters(nsIFilePicker.filterText);
+
+    // Link dialog also allows linking to images
+    if (filterType.indexOf("img") > 0)
+      fp.appendFilters(nsIFilePicker.filterImages);
+
+  }
+  // Default or last filter is "All Files"
+  fp.appendFilters(nsIFilePicker.filterAll);
+
+  // set the file picker's current directory to last-opened location saved in prefs
+  SetFilePickerDirectory(fp, fileType);
+
+
+  /* doesn't handle *.shtml files */
+  try {
+    var ret = fp.show();
+    if (ret == nsIFilePicker.returnCancel)
+      return null;
+  }
+  catch (ex) {
+    dump("filePicker.chooseInputFile threw an exception\n");
+    return null;
+  }
+  SaveFilePickerDirectory(fp, fileType);
+  
+  var fileHandler = GetFileProtocolHandler();
+  return fp.file ? fileHandler.getURLSpecFromFile(fp.file) : null;
+}
+
+function GetMetaElement(name)
+{
+  if (name)
+  {
+    name = name.toLowerCase();
+    if (name != "")
+    {
+      var editor = GetCurrentEditor();
+      try {
+        var metaNodes = editor.document.getElementsByTagName("meta");
+        for (var i = 0; i < metaNodes.length; i++)
+        {
+          var metaNode = metaNodes.item(i);
+          if (metaNode && metaNode.getAttribute("name") == name)
+            return metaNode;
+        }
+      } catch (e) {}
+    }
+  }
+  return null;
+}
+
+function CreateMetaElement(name)
+{
+  var editor = GetCurrentEditor();
+  try {
+    var metaElement = editor.createElementWithDefaults("meta");
+    metaElement.setAttribute("name", name);
+    return metaElement;
+  } catch (e) {}
+
+  return null;
+}
+
+function GetHTTPEquivMetaElement(name)
+{
+  if (name)
+  {
+    name = name.toLowerCase();
+    if (name != "")
+    {
+      var editor = GetCurrentEditor();
+      try {
+        var metaNodes = editor.document.getElementsByTagName("meta");
+        for (var i = 0; i < metaNodes.length; i++)
+        {
+          var metaNode = metaNodes.item(i);
+          if (metaNode)
+          {
+            var httpEquiv = metaNode.getAttribute("http-equiv");
+            if (httpEquiv && httpEquiv.toLowerCase() == name)
+              return metaNode;
+          }
+        }
+      } catch (e) {}
+    }
+  }
+  return null;
+}
+
+function CreateHTTPEquivMetaElement(name)
+{
+  var editor = GetCurrentEditor();
+  try {
+    var metaElement = editor.createElementWithDefaults("meta");
+    metaElement.setAttribute("http-equiv", name);
+    return metaElement;
+  } catch (e) {}
+
+  return null;
+}
+
+function CreateHTTPEquivElement(name)
+{
+  var editor = GetCurrentEditor();
+  try {
+    var metaElement = editor.createElementWithDefaults("meta");
+    metaElement.setAttribute("http-equiv", name);
+    return metaElement;
+  } catch (e) {}
+
+  return null;
+}
+
+// Change "content" attribute on a META element,
+//   or delete entire element it if content is empty
+// This uses undoable editor transactions
+function SetMetaElementContent(metaElement, content, insertNew, prepend)
+{
+  if (metaElement)
+  {
+    var editor = GetCurrentEditor();
+    try {
+      if(!content || content == "")
+      {
+        if (!insertNew)
+          editor.deleteNode(metaElement);
+      }
+      else
+      {
+        if (insertNew)
+        {
+          metaElement.setAttribute("content", content);
+          if (prepend)
+            PrependHeadElement(metaElement);
+          else
+            AppendHeadElement(metaElement);
+        }
+        else
+          editor.setAttribute(metaElement, "content", content);
+      }
+    } catch (e) {}
+  }
+}
+
+function GetHeadElement()
+{
+  var editor = GetCurrentEditor();
+  try {
+    var headList = editor.document.getElementsByTagName("head");
+    return headList.item(0);
+  } catch (e) {}
+
+  return null;
+}
+
+function PrependHeadElement(element)
+{
+  var head = GetHeadElement();
+  if (head)
+  {
+    var editor = GetCurrentEditor();
+    try {
+      // Use editor's undoable transaction
+      // Last param "true" says "don't change the selection"
+      editor.insertNode(element, head, 0, true);
+    } catch (e) {}
+  }
+}
+
+function AppendHeadElement(element)
+{
+  var head = GetHeadElement();
+  if (head)
+  {
+    var position = 0;
+    if (head.hasChildNodes())
+      position = head.childNodes.length;
+
+    var editor = GetCurrentEditor();
+    try {
+      // Use editor's undoable transaction
+      // Last param "true" says "don't change the selection"
+      editor.insertNode(element, head, position, true);
+    } catch (e) {}
+  }
+}
+
+function SetWindowLocation()
+{
+  gLocation = document.getElementById("location");
+  if (gLocation)
+  {
+    window.screenX = Math.max(0, Math.min(window.opener.screenX + Number(gLocation.getAttribute("offsetX")),
+                                          screen.availWidth - window.outerWidth));
+    window.screenY = Math.max(0, Math.min(window.opener.screenY + Number(gLocation.getAttribute("offsetY")),
+                                          screen.availHeight - window.outerHeight));
+  }
+}
+
+function SaveWindowLocation()
+{
+  if (gLocation)
+  {
+    var newOffsetX = window.screenX - window.opener.screenX;
+    var newOffsetY = window.screenY - window.opener.screenY;
+    gLocation.setAttribute("offsetX", window.screenX - window.opener.screenX);
+    gLocation.setAttribute("offsetY", window.screenY - window.opener.screenY);
+  }
+}
+
+function onCancel()
+{
+  SaveWindowLocation();
+  // Close dialog by returning true
+  return true;
+}
+
+function SetRelativeCheckbox(checkbox)
+{
+  if (!checkbox) {
+    checkbox = document.getElementById("MakeRelativeCheckbox");
+    if (!checkbox)
+      return;
+  }
+
+  var editor = GetCurrentEditor();
+  // Mail never allows relative URLs, so hide the checkbox
+  if (editor && (editor.flags & Components.interfaces.nsIPlaintextEditor.eEditorMailMask))
+  {
+    checkbox.collapsed = true;
+    return;
+  }
+
+  var input =  document.getElementById(checkbox.getAttribute("for"));
+  if (!input)
+    return;
+
+  var url = TrimString(input.value);
+  var urlScheme = GetScheme(url);
+
+  // Check it if url is relative (no scheme).
+  checkbox.checked = url.length > 0 && !urlScheme;
+
+  // Now do checkbox enabling:
+  var enable = false;
+
+  var docUrl = GetDocumentBaseUrl();
+  var docScheme = GetScheme(docUrl);
+
+  if (url && docUrl && docScheme)
+  {
+    if (urlScheme)
+    {
+      // Url is absolute
+      // If we can make a relative URL, then enable must be true!
+      // (this lets the smarts of MakeRelativeUrl do all the hard work)
+      enable = (GetScheme(MakeRelativeUrl(url)).length == 0);
+    }
+    else
+    {
+      // Url is relative
+      // Check if url is a named anchor
+      //  but document doesn't have a filename
+      // (it's probably "index.html" or "index.htm",
+      //  but we don't want to allow a malformed URL)
+      if (url[0] == "#")
+      {
+        var docFilename = GetFilename(docUrl);
+        enable = docFilename.length > 0;
+      }
+      else
+      {
+        // Any other url is assumed 
+        //  to be ok to try to make absolute
+        enable = true;
+      }
+    }
+  }
+
+  SetElementEnabled(checkbox, enable);
+}
+
+// oncommand handler for the Relativize checkbox in EditorOverlay.xul
+function MakeInputValueRelativeOrAbsolute(checkbox)
+{
+  var input =  document.getElementById(checkbox.getAttribute("for"));
+  if (!input)
+    return;
+
+  var docUrl = GetDocumentBaseUrl();
+  if (!docUrl)
+  {
+    // Checkbox should be disabled if not saved,
+    //  but keep this error message in case we change that
+    AlertWithTitle("", GetString("SaveToUseRelativeUrl"));
+    window.focus();
+  }
+  else 
+  {
+    // Note that "checked" is opposite of its last state,
+    //  which determines what we want to do here
+    if (checkbox.checked)
+      input.value = MakeRelativeUrl(input.value);
+    else
+      input.value = MakeAbsoluteUrl(input.value);
+
+    // Reset checkbox to reflect url state
+    SetRelativeCheckbox(checkbox);
+  }
+}
+
+var IsBlockParent = {
+  APPLET: true,
+  BLOCKQUOTE: true,
+  BODY: true,
+  CENTER: true,
+  DD: true,
+  DIV: true,
+  FORM: true,
+  LI: true,
+  NOSCRIPT: true,
+  OBJECT: true,
+  TD: true,
+  TH: true
+};
+
+var NotAnInlineParent = {
+  COL: true,
+  COLGROUP: true,
+  DL: true,
+  DIR: true,
+  MENU: true,
+  OL: true,
+  TABLE: true,
+  TBODY: true,
+  TFOOT: true,
+  THEAD: true,
+  TR: true,
+  UL: true
+};
+
+function nodeIsBreak(editor, node)
+{
+  return !node || node.localName == 'BR' || editor.nodeIsBlock(node);
+}
+
+function InsertElementAroundSelection(element)
+{
+  var editor = GetCurrentEditor();
+  editor.beginTransaction();
+
+  try {
+    // First get the selection as a single range
+    var range, start, end, offset;
+    var count = editor.selection.rangeCount;
+    if (count == 1)
+      range = editor.selection.getRangeAt(0).cloneRange();
+    else
+    {
+      range = editor.document.createRange();
+      start = editor.selection.getRangeAt(0)
+      range.setStart(start.startContainer, start.startOffset);
+      end = editor.selection.getRangeAt(--count);
+      range.setEnd(end.endContainer, end.endOffset);
+    }
+
+    // Flatten the selection to child nodes of the common ancestor
+    while (range.startContainer != range.commonAncestorContainer)
+      range.setStartBefore(range.startContainer);
+    while (range.endContainer != range.commonAncestorContainer)
+      range.setEndAfter(range.endContainer);
+
+    if (editor.nodeIsBlock(element))
+      // Block element parent must be a valid block
+      while (!(range.commonAncestorContainer.localName in IsBlockParent))
+        range.selectNode(range.commonAncestorContainer);
+    else
+    {
+      // Fail if we're not inserting a block (use setInlineProperty instead)
+      if (!nodeIsBreak(editor, range.commonAncestorContainer))
+        return false;
+      else if (range.commonAncestorContainer.localName in NotAnInlineParent)
+        // Inline element parent must not be an invalid block
+        do range.selectNode(range.commonAncestorContainer);
+        while (range.commonAncestorContainer.localName in NotAnInlineParent);
+      else
+        // Further insert block check
+        for (var i = range.startOffset; ; i++)
+          if (i == range.endOffset)
+            return false;
+          else if (nodeIsBreak(editor, range.commonAncestorContainer.childNodes[i]))
+            break;
+    }
+
+    // The range may be contained by body text, which should all be selected.
+    offset = range.startOffset;
+    start = range.startContainer.childNodes[offset];
+    if (!nodeIsBreak(editor, start))
+    {
+      while (!nodeIsBreak(editor, start.previousSibling))
+      {
+        start = start.previousSibling;
+        offset--;
+      }
+    }
+    end = range.endContainer.childNodes[range.endOffset];
+    if (end && !nodeIsBreak(editor, end.previousSibling))
+    {
+      while (!nodeIsBreak(editor, end))
+        end = end.nextSibling;
+    }
+
+    // Now insert the node
+    editor.insertNode(element, range.commonAncestorContainer, offset, true);
+    offset = element.childNodes.length;
+    if (!editor.nodeIsBlock(element))
+      editor.setShouldTxnSetSelection(false);
+
+    // Move all the old child nodes to the element
+    var empty = true;
+    while (start != end)
+    {
+      var next = start.nextSibling;
+      editor.deleteNode(start);
+      editor.insertNode(start, element, element.childNodes.length);
+      empty = false;
+      start = next;
+    }
+    if (!editor.nodeIsBlock(element))
+      editor.setShouldTxnSetSelection(true);
+    else
+    {
+      // Also move a trailing <br>
+      if (start && start.localName == 'BR')
+      {
+        editor.deleteNode(start);
+        editor.insertNode(start, element, element.childNodes.length);
+        empty = false;
+      }
+      // Still nothing? Insert a <br> so the node is not empty
+      if (empty)
+        editor.insertNode(editor.createElementWithDefaults("br"), element, element.childNodes.length);
+
+      // Hack to set the selection just inside the element
+      editor.insertNode(editor.document.createTextNode(""), element, offset);
+    }
+  }
+  finally {
+    editor.endTransaction();
+  }
+
+  return true;
+}
+
+function nodeIsBlank(node)
+{
+  return node && node.nodeType == Node.TEXT_NODE && !/\S/.test(node.data);
+}
+
+function nodeBeginsBlock(editor, node)
+{
+  while (nodeIsBlank(node))
+    node = node.nextSibling;
+  return nodeIsBreak(editor, node);
+}
+
+function nodeEndsBlock(editor, node)
+{
+  while (nodeIsBlank(node))
+    node = node.previousSibling;
+  return nodeIsBreak(editor, node);
+}
+
+// C++ function isn't exposed to JS :-(
+function RemoveBlockContainer(element)
+{
+  var editor = GetCurrentEditor();
+  editor.beginTransaction();
+
+  try {
+    var range = editor.document.createRange();
+    range.selectNode(element);
+    var offset = range.startOffset;
+    var parent = element.parentNode;
+
+    // May need to insert a break after the removed element
+    if (!nodeBeginsBlock(editor, element.nextSibling) &&
+        !nodeEndsBlock(editor, element.lastChild))
+      editor.insertNode(editor.createElementWithDefaults("br"), parent, range.endOffset);
+
+    // May need to insert a break before the removed element, or if it was empty
+    if (!nodeEndsBlock(editor, element.previousSibling) &&
+        !nodeBeginsBlock(editor, element.firstChild || element.nextSibling))
+      editor.insertNode(editor.createElementWithDefaults("br"), parent, offset++);
+
+    // Now remove the element
+    editor.deleteNode(element);
+
+    // Need to copy the contained nodes?
+    for (var i = 0; i < element.childNodes.length; i++)
+      editor.insertNode(element.childNodes[i].cloneNode(true), parent, offset++);
+  }
+  finally {
+    editor.endTransaction();
+  }
+}
+
+// C++ function isn't exposed to JS :-(
+function RemoveContainer(element)
+{
+  var editor = GetCurrentEditor();
+  editor.beginTransaction();
+
+  try {
+    var range = editor.document.createRange();
+    var parent = element.parentNode;
+    // Allow for automatic joining of text nodes
+    // so we can't delete the container yet
+    // so we need to copy the contained nodes
+    for (var i = 0; i < element.childNodes.length; i++) {
+      range.selectNode(element);
+      editor.insertNode(element.childNodes[i].cloneNode(true), parent, range.startOffset);
+    }
+    // Now remove the element
+    editor.deleteNode(element);
+  }
+  finally {
+    editor.endTransaction();
+  }
+}
+
+function FillLinkMenulist(linkMenulist, headingsArray)
+{
+  var menupopup = linkMenulist.firstChild;
+  var editor = GetCurrentEditor();
+  try {
+    var treeWalker = editor.document.createTreeWalker(editor.document, 1, null, true);
+    var headingList = [];
+    var anchorList = []; // for sorting
+    var anchorMap  = {}; // for weeding out duplicates and making heading anchors unique
+    var anchor;
+    var i;
+    for (var element = treeWalker.nextNode(); element; element = treeWalker.nextNode())
+    {
+      // grab headings
+      // Skip headings that already have a named anchor as their first child
+      //  (this may miss nearby anchors, but at least we don't insert another
+      //   under the same heading)
+      if (element instanceof HTMLHeadingElement && element.textContent &&
+          !(element.firstChild instanceof HTMLAnchorElement && element.firstChild.name))
+        headingList.push(element);
+
+      // grab named anchors
+      if (element instanceof HTMLAnchorElement && element.name)
+      {
+        anchor = '#' + element.name;
+        if (!(anchor in anchorMap))
+        {
+          anchorList.push({anchor: anchor, sortkey: anchor.toLowerCase()});
+          anchorMap[anchor] = true;
+        }
+      }
+      
+      // grab IDs
+      if (element.id)
+      {
+        anchor = '#' + element.id;
+        if (!(anchor in anchorMap))
+        {
+          anchorList.push({anchor: anchor, sortkey: anchor.toLowerCase()});
+          anchorMap[anchor] = true;
+        }
+      }
+    }
+    // add anchor for headings
+    for (i = 0; i < headingList.length; i++)
+    {
+      var heading = headingList[i];
+
+      // Use just first 40 characters, don't add "...",
+      //  and replace whitespace with "_" and strip non-word characters
+      anchor = '#' + ConvertToCDATAString(TruncateStringAtWordEnd(heading.textContent, 40, false));
+
+      // Append "_" to any name already in the list
+      while (anchor in anchorMap)
+        anchor += "_";
+      anchorList.push({anchor: anchor, sortkey: anchor.toLowerCase()});
+      anchorMap[anchor] = true;
+
+      // Save nodes in an array so we can create anchor node under it later
+      headingsArray[anchor] = heading;
+    }
+    if (anchorList.length)
+    {
+      // case insensitive sort
+      function compare(a, b)
+      {
+        if(a.sortkey < b.sortkey) return -1;
+        if(a.sortkey > b.sortkey) return 1;
+        return 0;
+      }
+      anchorList.sort(compare);
+
+      for (i = 0; i < anchorList.length; i++)
+        createMenuItem(menupopup,anchorList[i].anchor);
+    }
+    else
+    {
+      var item = createMenuItem(menupopup, GetString("NoNamedAnchorsOrHeadings"));
+      item.setAttribute("disabled", "true");
+    }
+  } catch (e) {}
+}
+
+function createMenuItem(aMenuPopup, aLabel)
+{
+  var menuitem = document.createElement("menuitem");
+  menuitem.setAttribute("label", aLabel);
+  aMenuPopup.appendChild(menuitem);
+  return menuitem;
+}
+
+// Shared by Image and Link dialogs for the "Choose" button for links
+function chooseLinkFile()
+{
+  // Get a local file, converted into URL format
+  var fileName = GetLocalFileURL("html, img");
+  if (fileName) 
+  {
+    // Always try to relativize local file URLs
+    if (gHaveDocumentUrl)
+      fileName = MakeRelativeUrl(fileName);
+
+    gDialog.hrefInput.value = fileName;
+
+    // Do stuff specific to a particular dialog
+    // (This is defined separately in Image and Link dialogs)
+    ChangeLinkLocation();
+  }
+  // Put focus into the input field
+  SetTextboxFocus(gDialog.hrefInput);
+}
+
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdDialogOverlay.xul
@@ -0,0 +1,109 @@
+<?xml version="1.0"?> 
+
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!DOCTYPE overlay SYSTEM "chrome://editor/locale/EdDialogOverlay.dtd">
+
+<overlay id="EdDialogOverlay"
+     xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+<vbox id="AdvancedEdit">
+  <hbox flex="1" style="margin-top: 0.2em" align="center">
+    <!-- This will right-align the button -->
+    <spacer flex="1"/>
+    <button id="AdvancedEditButton1" oncommand="onAdvancedEdit()" label="&AdvancedEditButton.label;"
+            accesskey="&AdvancedEditButton.accessKey;" tooltiptext="&AdvancedEditButton.tooltip;"/>
+  </hbox>
+  <separator class="groove"/>
+</vbox>
+
+<!-- Extra buttons to use when just button is needed
+     E.g. Image Properties Dialog switches position between 2 locations
+     Placed here to use same attributes as AdvancedEditButton button
+-->
+<button
+  id        = "AdvancedEditButton"
+  oncommand = "onAdvancedEdit();"
+  label     = "&AdvancedEditButton.label;"
+  accesskey = "&AdvancedEditButton.accessKey;"
+  tooltiptext="&AdvancedEditButton.tooltip;"/>
+
+<button 
+  id        = "AdvancedEditButton2" 
+  oncommand = "onAdvancedEdit()" 
+  label     = "&AdvancedEditButton.label;"
+  accesskey = "&AdvancedEditButton.accessKey;"
+  tooltiptext="&AdvancedEditButton.tooltip;"/>
+
+<button 
+  id        = "ChooseFile" 
+  oncommand = "chooseFile()"
+  label     = "&chooseFileButton.label;"
+  accesskey = "&chooseFileButton.accessKey;"/>
+
+<checkbox
+  id        = "MakeRelativeCheckbox"
+  label     = "&makeUrlRelative.label;"
+  accesskey = "&makeUrlRelative.accessKey;"
+  oncommand = "MakeInputValueRelativeOrAbsolute(this);"
+  tooltiptext = "&makeUrlRelative.tooltip;"/>
+
+<vbox id="LinkLocationBox">
+  <label control="hrefInput" accesskey="&LinkURLEditField.accessKey;" width="1">&LinkURLEditField.label;</label>
+  <textbox id="hrefInput" type="autocomplete"
+           autocompletesearch="history" timeout="50" maxrows="6"
+           disablehistory="false" class="uri-element"
+           oninput="ChangeLinkLocation();">
+    <menupopup class="autocomplete-history-popup"
+               popupalign="topleft" popupanchor="bottomleft"
+               oncommand="this.parentNode.value = event.target.getAttribute('label'); ChangeLinkLocation();"/>
+  </textbox>
+  <hbox align="center">
+    <!-- from EdDialogOverlay.xul 'for' identifies the textfield to get URL from -->
+    <checkbox id="MakeRelativeLink"
+              for="hrefInput"
+              label="&makeUrlRelative.label;"
+              accesskey="&makeUrlRelative.accessKey;"
+              oncommand="MakeInputValueRelativeOrAbsolute(this);"
+              tooltiptext="&makeUrlRelative.tooltip;"/>
+    <spacer flex="1"/>
+    <button label="&chooseFileLinkButton.label;" accesskey="&chooseFileLinkButton.accessKey;" oncommand="chooseLinkFile();"/>
+  </hbox>
+</vbox>  
+
+</overlay>    
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdDialogTemplate.js
@@ -0,0 +1,77 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+
+//Cancel() is in EdDialogCommon.js
+var insertNew = true;
+var tagname = "TAG NAME"
+
+// dialog initialization code
+function Startup()
+{
+  if (!GetCurrentEditor())
+  {
+    window.close();
+    return;
+  }
+  // gDialog is declared in EdDialogCommon.js
+  // Set commonly-used widgets like this:
+  gDialog.fooButton = document.getElementById("fooButton");
+
+  initDialog();
+  
+  // Set window location relative to parent window (based on persisted attributes)
+  SetWindowLocation();
+
+  // Set focus to first widget in dialog, e.g.:
+  SetTextboxFocus(gDialog.fooButton);
+}
+
+function InitDialog() 
+{
+  // Initialize all dialog widgets here,
+  // e.g., get attributes from an element for property dialog
+}
+
+function onAccept()
+{
+  // Validate all user data and set attributes and possibly insert new element here
+  // If there's an error the user must correct, return false to keep dialog open.
+  
+  SaveWindowLocation();
+  return true; // do close the window
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdDialogTemplate.xul
@@ -0,0 +1,61 @@
+<?xml version="1.0"?>
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<?xul-overlay href="chrome://global/content/dialogOverlay.xul"?> 
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?> 
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/Ed?????????.dtd">
+<!-- dialog containing a control requiring initial setup -->
+<dialog title="&windowTitle.label;"
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    onload="Startup()"
+    ondialogaccept="return onAccept();"
+    ondialogcancel="return onCancel();">
+
+  <!-- Methods common to all editor dialogs -->
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/Ed?????.js"/>
+  <script type="application/x-javascript" src="chrome://global/content/dialogOverlay.js" />
+
+  <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+  <broadcaster id="args" value=""/>
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdDictionary.js
@@ -0,0 +1,216 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var gSpellChecker;
+var gWordToAdd;
+
+function Startup()
+{
+  if (!GetCurrentEditor())
+  {
+    window.close();
+    return;
+  }
+  // Get the SpellChecker shell
+  if ("gSpellChecker" in window.opener && window.opener.gSpellChecker)
+    gSpellChecker = window.opener.gSpellChecker;
+
+  if (!gSpellChecker)
+  {
+    dump("SpellChecker not found!!!\n");
+    window.close();
+    return;
+  }
+  // The word to add word is passed as the 2nd extra parameter in window.openDialog()
+  gWordToAdd = window.arguments[1];
+  
+  gDialog.WordInput = document.getElementById("WordInput");
+  gDialog.DictionaryList = document.getElementById("DictionaryList");
+  
+  gDialog.WordInput.value = gWordToAdd;
+  FillDictionaryList();
+
+  // Select the supplied word if it is already in the list
+  SelectWordToAddInList();
+  SetTextboxFocus(gDialog.WordInput);
+}
+
+function ValidateWordToAdd()
+{
+  gWordToAdd = TrimString(gDialog.WordInput.value);
+  if (gWordToAdd.length > 0)
+  {
+    return true;
+  } else {
+    return false;
+  }
+}    
+
+function SelectWordToAddInList()
+{
+  for (var i = 0; i < gDialog.DictionaryList.getRowCount(); i++)
+  {
+
+    var wordInList = gDialog.DictionaryList.getItemAtIndex(i);
+    if (wordInList && gWordToAdd == wordInList.label)
+    {
+      gDialog.DictionaryList.selectedIndex = i;
+      break;
+    }
+  }
+}
+
+function AddWord()
+{
+  if (ValidateWordToAdd())
+  {
+    try {
+      gSpellChecker.AddWordToDictionary(gWordToAdd);
+    }
+    catch (e) {
+      dump("Exception occured in gSpellChecker.AddWordToDictionary\nWord to add probably already existed\n");
+    }
+
+    // Rebuild the dialog list
+    FillDictionaryList();
+
+    SelectWordToAddInList();
+    gDialog.WordInput.value = "";
+  }
+}
+
+function ReplaceWord()
+{
+  if (ValidateWordToAdd())
+  {
+    var selItem = gDialog.DictionaryList.selectedItem;
+    if (selItem)
+    {
+      try {
+        gSpellChecker.RemoveWordFromDictionary(selItem.label);
+      } catch (e) {}
+
+      try {
+        // Add to the dictionary list
+        gSpellChecker.AddWordToDictionary(gWordToAdd);
+
+        // Just change the text on the selected item
+        //  instead of rebuilding the list
+        selItem.label = gWordToAdd; 
+      } catch (e) {
+        // Rebuild list and select the word - it was probably already in the list
+        dump("Exception occured adding word in ReplaceWord\n");
+        FillDictionaryList();
+        SelectWordToAddInList();
+      }
+    }
+  }
+}
+
+function RemoveWord()
+{
+  var selIndex = gDialog.DictionaryList.selectedIndex;
+  if (selIndex >= 0)
+  {
+    var word = gDialog.DictionaryList.selectedItem.label;
+
+    // Remove word from list
+    gDialog.DictionaryList.removeItemAt(selIndex);
+
+    // Remove from dictionary
+    try {
+      //Not working: BUG 43348
+      gSpellChecker.RemoveWordFromDictionary(word);
+    }
+    catch (e)
+    {
+      dump("Failed to remove word from dictionary\n");
+    }
+
+    ResetSelectedItem(selIndex);
+  }
+}
+
+function FillDictionaryList()
+{
+  var selIndex = gDialog.DictionaryList.selectedIndex;
+
+  // Clear the current contents of the list
+  ClearListbox(gDialog.DictionaryList);
+
+  // Get the list from the spell checker
+  gSpellChecker.GetPersonalDictionary()
+
+  var haveList = false;
+
+  // Get words until an empty string is returned
+  do {
+    var word = gSpellChecker.GetPersonalDictionaryWord();
+    if (word != "")
+    {
+      gDialog.DictionaryList.appendItem(word, "");
+      haveList = true;
+    }
+  } while (word != "");
+  
+  //XXX: BUG 74467: If list is empty, it doesn't layout to full height correctly
+  //     (ignores "rows" attribute) (bug is latered, so we are fixing here for now)
+  if (!haveList)
+      gDialog.DictionaryList.appendItem("", "");
+
+  ResetSelectedItem(selIndex);
+}
+
+function ResetSelectedItem(index)
+{
+  var lastIndex = gDialog.DictionaryList.getRowCount() - 1;
+  if (index > lastIndex)
+    index = lastIndex;
+
+  // If we didn't have a selected item, 
+  //  set it to the first item
+  if (index == -1 && lastIndex >= 0)
+    index = 0;
+
+  gDialog.DictionaryList.selectedIndex = index;
+}
+
+function onClose()
+{
+  return true;
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdDictionary.xul
@@ -0,0 +1,91 @@
+<?xml version="1.0"?>
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorPersonalDictionary.dtd">
+<dialog buttons="cancel" title="&windowTitle.label;"
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    persist="screenX screenY"
+    onload = "Startup()"
+    ondialogcancel="return onClose();">
+
+  <!-- Methods common to all editor dialogs -->
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDictionary.js"/>
+  
+  <broadcaster id="args" value=""/>
+  <grid>
+    <columns><column style="width: 15em" flex="1"/><column flex="1"/></columns>
+    <rows>
+      <row>
+        <label value="&wordEditField.label;"
+               control="WordInput"
+               accesskey="&wordEditField.accessKey;"/>
+        <spacer/>
+      </row>
+      <row>
+        <textbox id="WordInput" flex="1"/>
+        <button id="AddWord" oncommand="AddWord()" label="&AddButton.label;"
+                accesskey="&AddButton.accessKey;"/>
+      </row>
+      <row>
+        <label value="&DictionaryList.label;"
+               control="DictionaryList"
+               accesskey="&DictionaryList.accessKey;"/>
+        <spacer/>
+      </row>
+      <row>
+        <listbox rows="8" id="DictionaryList" flex="1"/>
+        <vbox flex="1">
+          <button  id="ReplaceWord" oncommand="ReplaceWord()" label="&ReplaceButton.label;"
+                   accesskey="&ReplaceButton.accessKey;"/>
+          <spacer class="spacer"/>
+          <button  id="RemoveWord" oncommand="RemoveWord()" label="&RemoveButton.label;"
+                   accesskey="&RemoveButton.accessKey;"/>
+          <spacer class="spacer"/>
+          <spacer flex="1"/>
+          <button dlgtype="cancel" class="exit-dialog" id="close" label="&CloseButton.label;" 
+                  default="true" oncommand="onClose();"
+                  accesskey="&CloseButton.accessKey;"/>
+        </vbox>
+      </row>
+    </rows>
+  </grid>
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdFieldSetProps.js
@@ -0,0 +1,218 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Field Set Properties Dialog.
+ *
+ * The Initial Developer of the Original Code is
+ * Neil Rashbrook.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s): Neil Rashbrook <neil@parkwaycc.co.uk>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var insertNew;
+var fieldsetElement;
+var newLegend;
+var legendElement;
+
+// dialog initialization code
+
+function Startup()
+{
+  var editor = GetCurrentEditor();
+  if (!editor)
+  {
+    dump("Failed to get active editor!\n");
+    window.close();
+    return;
+  }
+
+  gDialog.editText = document.getElementById("EditText");
+  gDialog.legendText = document.getElementById("LegendText");
+  gDialog.legendAlign = document.getElementById("LegendAlign");
+  gDialog.RemoveFieldSet = document.getElementById("RemoveFieldSet");
+
+  // Get a single selected field set element
+  const kTagName = "fieldset";
+  try {
+    // Find a selected fieldset, or if one is at start or end of selection.
+    fieldsetElement = editor.getSelectedElement(kTagName);
+    if (!fieldsetElement)
+      fieldsetElement = editor.getElementOrParentByTagName(kTagName, editor.selection.anchorNode);
+    if (!fieldsetElement)
+      fieldsetElement = editor.getElementOrParentByTagName(kTagName, editor.selection.focusNode);
+  } catch (e) {}
+
+  if (fieldsetElement)
+    // We found an element and don't need to insert one
+    insertNew = false;
+  else
+  {
+    insertNew = true;
+
+    // We don't have an element selected,
+    //  so create one with default attributes
+    try {
+      fieldsetElement = editor.createElementWithDefaults(kTagName);
+    } catch (e) {}
+
+    if (!fieldsetElement)
+    {
+      dump("Failed to get selected element or create a new one!\n");
+      window.close();
+      return;
+    }
+    // Hide button removing existing fieldset
+    gDialog.RemoveFieldSet.hidden = true;
+  }
+
+  legendElement = fieldsetElement.firstChild;
+  if (legendElement && legendElement.localName == "LEGEND")
+  {
+    newLegend = false;
+    var range = editor.document.createRange();
+    range.selectNode(legendElement);
+    gDialog.legendText.value = range.toString();
+    if (/</.test(legendElement.innerHTML))
+    {
+      gDialog.editText.checked = false;
+      gDialog.editText.disabled = false;
+      gDialog.legendText.disabled = true;
+      gDialog.editText.addEventListener("command", onEditText, false);
+      gDialog.RemoveFieldSet.focus();
+    }
+    else
+      SetTextboxFocus(gDialog.legendText);
+  }
+  else
+  {
+    newLegend = true;
+
+    // We don't have an element selected,
+    //  so create one with default attributes
+
+    legendElement = editor.createElementWithDefaults("legend");
+    if (!legendElement)
+    {
+      dump("Failed to get selected element or create a new one!\n");
+      window.close();
+      return;
+    }
+    SetTextboxFocus(gDialog.legendText);
+  }
+
+  // Make a copy to use for AdvancedEdit
+  globalElement = legendElement.cloneNode(false);
+
+  InitDialog();
+
+  SetWindowLocation();
+}
+
+function InitDialog()
+{
+  gDialog.legendAlign.value = GetHTMLOrCSSStyleValue(globalElement, "align", "caption-side");
+}
+
+function onEditText()
+{
+  gDialog.editText.removeEventListener("command", onEditText, false);
+  AlertWithTitle(GetString("Alert"), GetString("EditTextWarning"));
+}
+
+function RemoveFieldSet()
+{
+  var editor = GetCurrentEditor();
+  editor.beginTransaction();
+  try {
+    if (!newLegend)
+      editor.deleteNode(legendElement);
+    RemoveBlockContainer(fieldsetElement);
+  } finally {
+    editor.endTransaction();
+  }
+  SaveWindowLocation();
+  window.close();
+}
+
+function ValidateData()
+{
+  if (gDialog.legendAlign.value)
+    globalElement.setAttribute("align", gDialog.legendAlign.value);
+  else
+    globalElement.removeAttribute("align");
+  return true;
+}
+
+function onAccept()
+{
+  // All values are valid - copy to actual element in doc
+  ValidateData();
+
+  var editor = GetCurrentEditor();
+
+  editor.beginTransaction();
+
+  try {
+    editor.cloneAttributes(legendElement, globalElement);
+ 
+    if (insertNew)
+    {
+      if (gDialog.legendText.value)
+      {
+        fieldsetElement.appendChild(legendElement);
+        legendElement.appendChild(editor.document.createTextNode(gDialog.legendText.value));
+      }
+      InsertElementAroundSelection(fieldsetElement);
+    }
+    else if (gDialog.editText.checked)
+    {
+      editor.setShouldTxnSetSelection(false);
+
+      if (gDialog.legendText.value)
+      {
+        if (newLegend)
+          editor.insertNode(legendElement, fieldsetElement, 0, true);
+        else while (legendElement.firstChild)
+          editor.deleteNode(legendElement.lastChild);
+        editor.insertNode(editor.document.createTextNode(gDialog.legendText.value), legendElement, 0);
+      }
+      else if (!newLegend)
+        editor.deleteNode(legendElement);
+
+      editor.setShouldTxnSetSelection(true);
+    }
+  }
+  finally {
+    editor.endTransaction();
+  }
+
+  SaveWindowLocation();
+
+  return true;
+}
+
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdFieldSetProps.xul
@@ -0,0 +1,91 @@
+<?xml version="1.0"?>
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Field Set Properties Dialog.
+   -
+   - The Initial Developer of the Original Code is
+   - Neil Rashbrook.
+   - Portions created by the Initial Developer are Copyright (C) 2001
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s): Neil Rashbrook <neil@parkwaycc.co.uk>
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either the GNU General Public License Version 2 or later (the "GPL"), or
+   - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the LGPL or the GPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?> 
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorFieldSetProperties.dtd">
+<dialog title="&windowTitle.label;"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        onload="Startup();"
+        buttons="accept,cancel"
+        ondialogaccept="return onAccept();"
+        ondialogcancel="return onCancel();">
+
+  <!-- Methods common to all editor dialogs -->
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdFieldSetProps.js"/>
+
+  <broadcaster id="args" value=""/>
+  <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+  <groupbox><caption label="&Legend.label;" accesskey="&Legend.accesskey;"/>
+    <grid><columns><column/><column/></columns>
+      <rows>
+        <row align="center">
+          <checkbox id="EditText" label="&EditLegendText.label;" accesskey="&EditLegendText.accesskey;" checked="true" disabled="true"
+            oncommand="gDialog.legendText.disabled = !gDialog.editText.checked;"/>
+          <textbox id="LegendText" accesskey="&Legend.accesskey;"/>
+        </row>
+        <row align="center">
+          <label control="LegendAlign" value="&LegendAlign.label;" accesskey="&LegendAlign.accesskey;"/>
+          <menulist id="LegendAlign">
+            <menupopup>
+              <menuitem label="&AlignDefault.label;"/>
+              <menuitem label="&AlignLeft.label;" value="left"/>
+              <menuitem label="&AlignCenter.label;" value="center"/>
+              <menuitem label="&AlignRight.label;" value="right"/>
+            </menupopup>
+          </menulist>
+        </row>
+      </rows>
+    </grid>
+  </groupbox>
+
+  <!-- from EdDialogOverlay -->
+  <hbox flex="1" style="margin-top: 0.2em">
+    <button id="RemoveFieldSet" label="&RemoveFieldSet.label;" accesskey="&RemoveFieldSet.accesskey;" oncommand="RemoveFieldSet();"/>
+    <!-- This will right-align the button -->
+    <spacer flex="1"/>
+    <button id="AdvancedEditButton"/>
+  </hbox>
+  <separator class="groove"/>
+
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdFormProps.js
@@ -0,0 +1,160 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Form Properties Dialog.
+ *
+ * The Initial Developer of the Original Code is
+ * Neil Rashbrook.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s): Neil Rashbrook <neil@parkwaycc.co.uk>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var gForm;
+var insertNew;
+var formElement;
+var formActionWarning;
+
+function Startup()
+{
+  var editor = GetCurrentEditor();
+  if (!editor)
+  {
+    dump("Failed to get active editor!\n");
+    window.close();
+    return;
+  }
+
+  gForm = {
+    Name:     document.getElementById("FormName"),
+    Action:   document.getElementById("FormAction"),
+    Method:   document.getElementById("FormMethod"),
+    EncType:  document.getElementById("FormEncType"),
+    Target:   document.getElementById("FormTarget")
+  }
+  gDialog.MoreSection = document.getElementById("MoreSection");
+  gDialog.MoreFewerButton = document.getElementById("MoreFewerButton");
+  gDialog.RemoveForm = document.getElementById("RemoveForm")
+
+  // Get a single selected form element
+  const kTagName = "form";
+  try {
+    formElement = editor.getSelectedElement(kTagName);
+    if (!formElement)
+      formElement = editor.getElementOrParentByTagName(kTagName, editor.selection.anchorNode);
+    if (!formElement)
+      formElement = editor.getElementOrParentByTagName(kTagName, editor.selection.focusNode);
+  } catch (e) {}
+
+  if (formElement)
+  {
+    // We found an element and don't need to insert one
+    insertNew = false;
+    formActionWarning = formElement.hasAttribute("action");
+  }
+  else
+  {
+    insertNew = true;
+    formActionWarning = true;
+
+    // We don't have an element selected,
+    //  so create one with default attributes
+    try {
+      formElement = editor.createElementWithDefaults(kTagName);
+    } catch (e) {}
+
+    if (!formElement)
+    {
+      dump("Failed to get selected element or create a new one!\n");
+      window.close();
+      return;
+    }
+    // Hide button removing existing form
+    gDialog.RemoveForm.hidden = true;
+  }
+
+  // Make a copy to use for AdvancedEdit
+  globalElement = formElement.cloneNode(false);
+
+  InitDialog();
+
+  InitMoreFewer();
+
+  SetTextboxFocus(gForm.Name);
+
+  SetWindowLocation();
+}
+
+function InitDialog()
+{
+  for (var attribute in gForm)
+    gForm[attribute].value = globalElement.getAttribute(attribute);
+}
+
+function RemoveForm()
+{
+  RemoveBlockContainer(formElement);
+  SaveWindowLocation();
+  window.close();
+}
+
+function ValidateData()
+{
+  for (var attribute in gForm)
+  {
+    if (gForm[attribute].value)
+      globalElement.setAttribute(attribute, gForm[attribute].value);
+    else
+      globalElement.removeAttribute(attribute);
+  }
+  return true;
+}
+
+function onAccept()
+{
+  if (formActionWarning && !gForm.Action.value)
+  {
+    AlertWithTitle(GetString("Alert"), GetString("NoFormAction"));
+    gForm.Action.focus();
+    formActionWarning = false;
+    return false;
+  }
+  // All values are valid - copy to actual element in doc or
+  //   element created to insert
+  ValidateData();
+
+  var editor = GetCurrentEditor();
+
+  editor.cloneAttributes(formElement, globalElement);
+
+  if (insertNew)
+    InsertElementAroundSelection(formElement);
+
+  SaveWindowLocation();
+
+  return true;
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdFormProps.xul
@@ -0,0 +1,120 @@
+<?xml version="1.0"?>
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Form Properties Dialog.
+   -
+   - The Initial Developer of the Original Code is
+   - Neil Rashbrook.
+   - Portions created by the Initial Developer are Copyright (C) 2001
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s): Neil Rashbrook <neil@parkwaycc.co.uk>
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either the GNU General Public License Version 2 or later (the "GPL"), or
+   - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the LGPL or the GPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?> 
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorFormProperties.dtd">
+<dialog title="&windowTitle.label;"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        onload="Startup();"
+        buttons="accept,cancel"
+        ondialogaccept="return onAccept();"
+        ondialogcancel="return onCancel();">
+
+  <!-- Methods common to all editor dialogs -->
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdFormProps.js"/>
+
+  <broadcaster id="args" value=""/>
+  <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+  <groupbox><caption label="&Settings.label;"/>
+    <grid><columns><column/><column/></columns>
+      <rows>
+        <row align="center">
+          <label control="FormName" value="&FormName.label;" accesskey="&FormName.accesskey;"/>
+          <textbox id="FormName"/>
+        </row>
+        <row align="center">
+          <label control="FormAction" value="&FormAction.label;" accesskey="&FormAction.accesskey;"/>
+          <textbox id="FormAction"/>
+        </row>
+        <row align="center">
+          <label control="FormMethod" value="&FormMethod.label;" accesskey="&FormMethod.accesskey;"/>
+          <hbox>
+            <menulist id="FormMethod" editable="true" autoSelectMenuitem="true">
+              <menupopup>
+                <menuitem label="GET"/>
+                <menuitem label="POST"/>
+              </menupopup>
+            </menulist>
+          </hbox>
+        </row>
+        <hbox>
+          <button id="MoreFewerButton" oncommand="onMoreFewer();" persist="more"/>
+        </hbox>
+        <rows id="MoreSection">
+          <row align="center">
+            <label control="FormEncType" value="&FormEncType.label;" accesskey="&FormEncType.accesskey;"/>
+            <menulist id="FormEncType" editable="true" autoSelectMenuitem="true">
+              <menupopup>
+                <menuitem label="application/x-www-form-urlencoded"/>
+                <menuitem label="multipart/form-data"/>
+                <menuitem label="text/plain"/>
+              </menupopup>
+            </menulist>
+          </row>
+          <row align="center">
+            <label control="FormTarget" value="&FormTarget.label;" accesskey="&FormTarget.accesskey;"/>
+            <menulist id="FormTarget" editable="true" autoSelectMenuitem="true">
+              <menupopup>
+                <menuitem label="_blank"/>
+                <menuitem label="_self"/>
+                <menuitem label="_parent"/>
+                <menuitem label="_top"/>
+              </menupopup>
+            </menulist>
+          </row>
+        </rows>
+      </rows>
+    </grid>
+  </groupbox>
+
+  <!-- from EdDialogOverlay -->
+  <hbox flex="1" style="margin-top: 0.2em">
+    <button id="RemoveForm" label="&RemoveForm.label;" accesskey="&RemoveForm.accesskey;" oncommand="RemoveForm();"/>
+    <!-- This will right-align the button -->
+    <spacer flex="1"/>
+    <button id="AdvancedEditButton"/>
+  </hbox>
+  <separator class="groove"/>
+
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdHLineProps.js
@@ -0,0 +1,234 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var tagName = "hr";
+var gHLineElement;
+var width;
+var height;
+var align;
+var shading;
+const gMaxHRSize = 1000; // This is hard-coded in nsHTMLHRElement::StringToAttribute()
+
+// dialog initialization code
+function Startup()
+{
+  var editor = GetCurrentEditor();
+  if (!editor)
+  {
+    window.close();
+    return;
+  }
+  try {
+    // Get the selected horizontal line
+    gHLineElement = editor.getSelectedElement(tagName);
+  } catch (e) {}
+
+  if (!gHLineElement) {
+    // We should never be here if not editing an existing HLine
+    window.close();
+    return;
+  }
+  gDialog.heightInput = document.getElementById("height");
+  gDialog.widthInput = document.getElementById("width");
+  gDialog.leftAlign = document.getElementById("leftAlign");
+  gDialog.centerAlign = document.getElementById("centerAlign");
+  gDialog.rightAlign = document.getElementById("rightAlign");
+  gDialog.alignGroup = gDialog.rightAlign.radioGroup;
+  gDialog.shading = document.getElementById("3dShading");
+  gDialog.pixelOrPercentMenulist = document.getElementById("pixelOrPercentMenulist");
+
+  // Make a copy to use for AdvancedEdit and onSaveDefault
+  globalElement = gHLineElement.cloneNode(false);
+
+  // Initialize control values based on existing attributes
+  InitDialog()
+
+  // SET FOCUS TO FIRST CONTROL
+  SetTextboxFocus(gDialog.widthInput);
+
+  // Resize window
+  window.sizeToContent();
+
+  SetWindowLocation();
+}
+
+// Set dialog widgets with attribute data
+// We get them from globalElement copy so this can be used
+//   by AdvancedEdit(), which is shared by all property dialogs
+function InitDialog()
+{
+  // Just to be confusing, "size" is used instead of height because it does
+  // not accept % values, only pixels
+  var height = GetHTMLOrCSSStyleValue(globalElement, "size", "height")
+  if (/px/.test(height)) {
+    height = RegExp.leftContext;
+  }
+  if(!height) {
+    height = 2; //Default value
+  }
+
+  // We will use "height" here and in UI
+  gDialog.heightInput.value = height;
+
+  // Get the width attribute of the element, stripping out "%"
+  // This sets contents of menulist (adds pixel and percent menuitems elements)
+  gDialog.widthInput.value = InitPixelOrPercentMenulist(globalElement, gHLineElement, "width","pixelOrPercentMenulist");
+
+  var marginLeft  = GetHTMLOrCSSStyleValue(globalElement, "align", "margin-left").toLowerCase();
+  var marginRight = GetHTMLOrCSSStyleValue(globalElement, "align", "margin-right").toLowerCase();
+  align = marginLeft + " " + marginRight;
+  gDialog.leftAlign.checked   = (align == "left left"     || align == "0px auto");
+  gDialog.centerAlign.checked = (align == "center center" || align == "auto auto" || align == " ");
+  gDialog.rightAlign.checked  = (align == "right right"   || align == "auto 0px");
+
+  if (gDialog.centerAlign.checked) {
+    gDialog.alignGroup.selectedItem = gDialog.centerAlign;
+  }
+  else if (gDialog.rightAlign.checked) {
+    gDialog.alignGroup.selectedItem = gDialog.rightAlign;
+  }
+  else {
+    gDialog.alignGroup.selectedItem = gDialog.leftAlign;
+  }
+
+  gDialog.shading.checked = !globalElement.hasAttribute("noshade");
+}
+
+function onSaveDefault()
+{
+  // "false" means set attributes on the globalElement,
+  //   not the real element being edited
+  if (ValidateData()) {
+    var prefs = GetPrefs();
+    if (prefs) {
+
+      var alignInt;
+      if (align == "left") {
+        alignInt = 0;
+      } else if (align == "right") {
+        alignInt = 2;
+      } else {
+        alignInt = 1;
+      }
+      prefs.setIntPref("editor.hrule.align", alignInt);
+
+      var percent;
+      var widthInt;
+      var heightInt;
+
+      if (width)
+      {
+        if (/%/.test(width)) {
+          percent = true;
+          widthInt = Number(RegExp.leftContext);
+        } else {
+          percent = false;
+          widthInt = Number(width);
+        }
+      }
+      else
+      {
+        percent = true;
+        widthInt = Number(100);
+      }
+
+      heightInt = height ? Number(height) : 2;
+
+      prefs.setIntPref("editor.hrule.width", widthInt);
+      prefs.setBoolPref("editor.hrule.width_percent", percent);
+      prefs.setIntPref("editor.hrule.height", heightInt);
+      prefs.setBoolPref("editor.hrule.shading", shading);
+
+      // Write the prefs out NOW!
+      var prefService = Components.classes["@mozilla.org/preferences-service;1"]
+                                  .getService(Components.interfaces.nsIPrefService);
+      prefService.savePrefFile(null);
+    }
+	}
+}
+
+// Get and validate data from widgets.
+// Set attributes on globalElement so they can be accessed by AdvancedEdit()
+function ValidateData()
+{
+  // Height is always pixels
+  height = ValidateNumber(gDialog.heightInput, null, 1, gMaxHRSize,
+                          globalElement, "size", false);
+  if (gValidationError)
+    return false;
+
+  width = ValidateNumber(gDialog.widthInput, gDialog.pixelOrPercentMenulist, 1, gMaxPixels, 
+                         globalElement, "width", false);
+  if (gValidationError)
+    return false;
+
+  align = "left";
+  if (gDialog.centerAlign.selected) {
+    // Don't write out default attribute
+    align = "";
+  } else if (gDialog.rightAlign.selected) {
+    align = "right";
+  }
+  if (align)
+    globalElement.setAttribute("align", align);
+  else
+    try {
+      GetCurrentEditor().removeAttributeOrEquivalent(globalElement, "align", true);
+    } catch (e) {}
+
+  if (gDialog.shading.checked) {
+    shading = true;
+    globalElement.removeAttribute("noshade");
+  } else {
+    shading = false;
+    globalElement.setAttribute("noshade", "noshade");
+  }
+  return true;
+}
+
+function onAccept()
+{
+  if (ValidateData())
+  {
+    // Copy attributes from the globalElement to the document element
+    try {
+      GetCurrentEditor().cloneAttributes(gHLineElement, globalElement);
+    } catch (e) {}
+    return true;
+  }
+  return false;
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdHLineProps.xul
@@ -0,0 +1,104 @@
+<?xml version="1.0"?>
+
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?> 
+<?xul-overlay href="chrome://global/content/globalOverlay.xul"?>
+<?xul-overlay href="chrome://communicator/content/utilityOverlay.xul"?> 
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorHLineProperties.dtd">
+
+<dialog title="&windowTitle.label;"
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    onload="Startup()"
+    ondialogaccept="return onAccept();"
+    ondialogcancel="return onCancel();">
+
+  <!-- Methods common to all editor dialogs -->
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <!--- Element-specific methods -->
+  <script type="application/x-javascript" src="chrome://editor/content/EdHLineProps.js"/>
+
+  <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+  
+  <groupbox><caption label="&dimensionsBox.label;"/>
+    <grid>
+      <columns><column/><column/><column /></columns>
+      <rows>
+        <row align="center">
+          <label control="width"
+                 value="&widthEditField.label;"
+                 accesskey="&widthEditField.accessKey;"/>
+          <textbox class="narrow" id="width" flex="1" oninput="forceInteger('width')"/>
+          <menulist id="pixelOrPercentMenulist" />
+          <!-- menupopup and menuitems added by JS -->
+        </row>
+        <row align="center">
+          <label control="height"
+                 value="&heightEditField.label;"
+                 accesskey="&heightEditField.accessKey;"/>
+          <textbox class="narrow" id="height" oninput="forceInteger('height')"/>
+          <label value="&pixelsPopup.value;" />
+        </row>
+      </rows>
+    </grid>        
+    <checkbox id="3dShading" label="&threeDShading.label;" accesskey="&threeDShading.accessKey;"/>
+  </groupbox>
+  <groupbox><caption label="&alignmentBox.label;"/>
+    <radiogroup id="alignmentGroup" orient="horizontal">
+      <spacer class="spacer"/>
+      <radio id="leftAlign"   label="&leftRadio.label;"   accesskey="&leftRadio.accessKey;"/>
+      <radio id="centerAlign" label="&centerRadio.label;" accesskey="&centerRadio.accessKey;"/>
+      <radio id="rightAlign"  label="&rightRadio.label;"  accesskey="&rightRadio.accessKey;"/>
+    </radiogroup>
+  </groupbox>
+  <spacer class="spacer"/>
+  <hbox>
+    <button  id="SaveDefault" label="&saveSettings.label;" 
+         accesskey="&saveSettings.accessKey;"
+         oncommand="onSaveDefault()"
+         tooltiptext="&saveSettings.tooltip;" />
+    <spacer flex="1"/>
+    <button id="AdvancedEditButton"/>
+  </hbox>
+  <separator class="groove"/>
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdImageMap.js
@@ -0,0 +1,373 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Dan Haddix (dan6992@hotmail.com)
+ *   Brian King (briano9@yahoo.com)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var tHide = false;
+var highCont = false;
+var imageElement = null;
+var mapName = '';
+var imageMap = null;
+var imageEl;
+var srcInputValue = null;
+var marquee = null;
+var frameDoc = null;
+var buttonArray = [];
+
+function Startup(){
+  if (!GetCurrentEditor())
+  {
+    window.close();
+    return;
+  }
+  initDialog();
+}
+
+function initDialog(){
+  //Get image element from parent
+  imageElement = window.arguments[0];
+  if (!imageElement) //If not an image close window
+  {
+    window.close();
+    return;
+  }
+
+  //Get image map from parent
+  imageMap = window.arguments[1];
+  if (!imageMap) //If no image map close window
+    window.close();
+
+  //find parent inputs
+  var srcInput = window.opener.document.getElementById("srcInput");
+  var widthInput = window.opener.document.getElementById("widthInput");
+  var heightInput = window.opener.document.getElementById("heightInput");
+
+  //check for relative url
+  if (!((srcInput.value.indexOf("http://") != -1) || (srcInput.value.indexOf("file://") != -1))){
+    if (IsUrlAboutBlank(GetDocumentUrl())){
+      alert(GetString("SaveToUseRelativeUrl"));
+      window.close();
+      //TODO: add option to save document now
+    }
+    else{
+      var edDoc = GetDocumentUrl();
+      var imgDoc = srcInput.value;
+      imgDoc = imgDoc.split("../");
+      var len = imgDoc.length;
+      for (var i=0; i<len; i++){
+        if (edDoc.length > (String(GetCurrentEditor().document.location.protocol).length+2))
+          edDoc = edDoc.substring(0, edDoc.lastIndexOf("/"));
+      }
+      imgDoc = edDoc+"/"+imgDoc[imgDoc.length-1];
+      srcInputValue = imgDoc;
+    }
+  }
+  else{
+    srcInputValue = srcInput.value;
+  }
+
+  //Set iframe pointer
+  frameDoc = window.frames[0].document;
+
+  //Fill button array
+  buttonArray[0] = document.getElementById("pointerButton");
+  buttonArray[1] = document.getElementById("rectButton");
+  buttonArray[2] = document.getElementById("cirButton");
+  buttonArray[3] = document.getElementById("polyButton");
+
+  //Create marquee
+  var marquee = frameDoc.createElement("div");
+  marquee.setAttribute("id", "marquee");
+  frameDoc.body.appendChild(marquee);
+
+  //Create background div
+  var bgDiv = frameDoc.createElement("div");
+  if ( bgDiv ) {
+    bgDiv.setAttribute("id", "bgDiv");
+    frameDoc.body.appendChild(bgDiv);
+  }
+
+  //Place Image
+  var newImg = frameDoc.createElement("img");
+  if ( newImg ) {
+    newImg.setAttribute("src", srcInputValue);
+    if (parseInt(widthInput.value) > 0)
+      newImg.setAttribute("width", widthInput.value);
+    if (parseInt(heightInput.value) > 0)
+      newImg.setAttribute("height", heightInput.value);
+    newImg.setAttribute("id", "mainImg");
+    imageEl = frameDoc.getElementById("bgDiv").appendChild(newImg);
+    imageEl.addEventListener("error", imgError, false);
+  }
+
+  //Resize background DIV to fit image
+  fixBgDiv();
+
+  //Recreate Image Map if it exists
+  recreateMap();
+}
+
+function imgError(){
+  alert(GetString("ImapError")+" " + srcInputValue+"."+GetString("ImapCheck"));
+}
+
+function fixBgDiv(){
+  imageEl = frameDoc.getElementById("mainImg");
+  if (imageEl.offsetWidth != 0){
+    frameDoc.getElementById("bgDiv").style.width = imageEl.offsetWidth;
+    frameDoc.getElementById("bgDiv").style.height = imageEl.offsetHeight;
+  }
+  else
+    setTimeout("fixBgDiv()", 100);
+}
+
+function hideToolbar(){
+  // Check to see if toolbar is already hidden
+  if (tHide){
+    // If it is show it
+    document.getElementById("toolbar").collapsed = false;
+    // Set the menu items text back to "Hide Toolbar"
+    document.getElementById("view_hidetoolbar").setAttribute("label", GetString("HideToolbar"));
+    tHide = false
+  }
+  else{
+    // If not hide it
+    document.getElementById("toolbar").collapsed = true;
+    //Set the menu items text to "Show Toolbar"
+    document.getElementById("view_hidetoolbar").setAttribute("label", GetString("ShowToolbar"));
+    tHide = true;
+  }
+}
+
+function highContrast(){
+  if (highCont == true){
+    frameDoc.getElementById("bgDiv").style.background = "url('chrome://editor/skin/images/Map_checker.gif')";
+    frameDoc.getElementById("bgDiv").style.backgroundColor = "white";
+    imageEl.style.setProperty("opacity", "1.0", true);
+    document.getElementById("Map:Contrast").setAttribute("checked", "false");
+    document.getElementById("Map:Contrast").setAttribute("toggled", "false");
+    highCont = false;
+  }
+  else{
+    frameDoc.getElementById("bgDiv").style.background = "url('')";
+    frameDoc.getElementById("bgDiv").style.backgroundColor = "#D2D2D2";
+    imageEl.style.setProperty("opacity", ".3", true);
+    document.getElementById("Map:Contrast").setAttribute("checked", "true");
+    document.getElementById("Map:Contrast").setAttribute("toggled", "true");
+    highCont = true;
+  }
+}
+
+function recreateMap(){
+  var areaCollection = imageMap.childNodes;
+  var areaColLen = areaCollection.length;
+  for(var j=0; j<areaColLen; j++){
+      area = areaCollection[j];
+      shape = area.getAttribute("shape");
+      shape = shape.toLowerCase();
+      coords = area.getAttribute("coords");
+      href = area.getAttribute("href");
+      target = area.getAttribute("target");
+      alt = area.getAttribute("alt");
+      if (shape == "rect")
+        Rect(coords, href, target, alt, true);
+      else if (shape == "circle")
+        Circle(coords, href, target, alt, true);
+      else
+        Poly(coords, href, target, alt, true);
+    }
+}
+
+function finishMap(){
+  if (!setMapName())
+    return false;
+  if (!deleteAreas())
+    return false;
+
+  spots = frameDoc.getElementsByName("hotspot");
+  var len = spots.length;
+  if (len >= 1){
+    for(i=0; i<len; i++){
+      dump(i+"\n");
+      curSpot = spots[i];
+      if (curSpot.getAttribute("class") == "rect")
+        createRect(curSpot);
+      else if (curSpot.getAttribute("class") == "cir")
+        createCir(curSpot);
+      else
+        createPoly(curSpot);
+    }
+    //try{
+    //  GetCurrentEditor().root.appendChild(imageMap);
+    //} catch (e) {}
+    //returnValue = "test";
+    //try{
+    //  window.arguments[0] = "test"; //GetCurrentEditor().insertElementAtSelection(imageMap, false);
+    //  dump(window.arguments[0]+"\n");
+    //} catch (e) {}
+    dump("imageMap.childNodes.length = "+imageMap.childNodes.length+"\n");
+  }
+  return true;
+}
+
+function setMapName() {
+  //try {
+  //  imageMap = GetCurrentEditor().createElementWithDefaults("map");
+  //} catch (e) {}
+  //dump(imageMap+"\n");
+  //imageMap = frameDoc.createElement("map");
+
+  mapName = imageMap.getAttribute("name");
+  if (mapName == ""){
+    mapName = String(frameDoc.getElementById("mainImg").getAttribute("src"));
+  mapName = mapName.substring(mapName.lastIndexOf("/"), mapName.length);
+  mapName = mapName.substring(mapName.lastIndexOf("\\"), mapName.length);
+    mapName = mapName.substring(1, mapName.lastIndexOf("."));
+    if (mapName == ""){
+      // BUG causes substring to return nothing when
+      // parameters are 1 & 13 (i.e. string.substring(1, 13);)
+      mapName = "hack";
+  }
+  imageMap.setAttribute("name", mapName);
+}
+  return true;
+}
+
+function createRect(which){
+  var newRect;
+  //try {
+  //  newRect = editor.createElementWithDefaults("area");
+  //} catch (e) {}
+  newRect = frameDoc.createElement("area");
+  newRect.setAttribute("shape", "rect");
+  coords = parseInt(which.style.left)+","+parseInt(which.style.top)+","+(parseInt(which.style.left)+parseInt(which.style.width))+","+(parseInt(which.style.top)+parseInt(which.style.height));
+  newRect.setAttribute("coords", coords);
+  if (which.getAttribute("hsHref") != ""){
+    newRect.setAttribute("href", which.getAttribute("hsHref"));
+  }
+  else{
+    newRect.setAttribute("nohref", "");
+  }
+  if (which.getAttribute("hsTarget") != ""){
+  newRect.setAttribute("target", which.getAttribute("hsTarget"));
+  }
+  if (which.getAttribute("hsAlt") != ""){
+  newRect.setAttribute("alt", which.getAttribute("hsAlt"));
+  }
+  //newRect.removeAttribute("id");
+  imageMap.appendChild(newRect);
+}
+
+function createCir(which){
+  var newCir;
+  //try {
+  //  newCir = editor.createElementWithDefaults("area");
+  //} catch (e) {}
+  newCir = frameDoc.createElement("area");
+  if ( !newCir )
+    return;
+
+  newCir.setAttribute("shape", "circle");
+  radius = Math.floor(parseInt(which.style.width)/2);
+  coords = (parseInt(which.style.left)+radius)+","+(parseInt(which.style.top)+radius)+","+radius;
+  newCir.setAttribute("coords", coords);
+  if (which.getAttribute("hsHref") != "")
+    newCir.setAttribute("href", which.getAttribute("hsHref"));
+  else{
+    newCir.setAttribute("nohref", "");
+  }
+  if (which.getAttribute("hsTarget") != ""){
+    newCir.setAttribute("target", which.getAttribute("hsTarget"));
+  }
+  if (which.getAttribute("hsAlt") != ""){
+    newCir.setAttribute("alt", which.getAttribute("hsAlt"));
+  }
+  //newCir.removeAttribute("id");
+  imageMap.appendChild(newCir);
+}
+
+function createPoly(which){
+  var newPoly;
+  //try {
+  //  newPoly = editor.createElementWithDefaults("area");
+  //} catch (e) {}
+  newPoly = frameDoc.createElement("area");
+  if ( !newPoly )
+    return;
+
+  newPoly.setAttribute("shape", "poly");
+  var coords = '';
+  var len = which.childNodes.length;
+  for(l=0; l<len; l++){
+    coords += (parseInt(which.style.left)+parseInt(which.childNodes[l].style.left))+","+(parseInt(which.style.top)+parseInt(which.childNodes[l].style.top))+",";
+  }
+  coords = coords.substring(0, (coords.length-1));
+  newPoly.setAttribute("coords", coords);
+  if (which.getAttribute("hsHref") != "")
+    newPoly.setAttribute("href", which.getAttribute("hsHref"));
+  else{
+    newPoly.setAttribute("nohref", "");
+  }
+  if (which.getAttribute("hsTarget") != ""){
+    newPoly.setAttribute("target", which.getAttribute("hsTarget"));
+  }
+  if (which.getAttribute("hsAlt") != ""){
+    newPoly.setAttribute("alt", which.getAttribute("hsAlt"));
+  }
+  //newPoly.removeAttribute("id");
+  imageMap.appendChild(newPoly);
+}
+
+function hotSpotProps(which){
+  var currentRect = null;
+  var currentCir = null;
+  if (which == null)
+    return;
+  hotSpotWin = window.openDialog("chrome://editor/content/EdImageMapHotSpot.xul", "_blank", "chrome,close,titlebar,modal", which);
+}
+
+function deleteAreas(){
+  dump("deleteAreas called\n");
+  area = imageMap.firstChild;
+  while (area != null){
+    dump(area+"\n");
+    imageMap.removeChild(area);
+    area = imageMap.firstChild;
+  }
+  return true;
+}
+
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdImageMap.xul
@@ -0,0 +1,181 @@
+<?xml version="1.0"?>
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1999-2000
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -   - Brian King (briano9@yahoo.com)
+   -   - Dan Haddix (dan6992@hotmail.com)
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/EdImageMap.css" type="text/css"?> 
+<?xml-stylesheet href="chrome://editor/skin/" type="text/css"?>
+
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?> 
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorImageMap.dtd">
+
+<!-- dialog containing a control requiring initial setup -->
+<dialog title="&windowTitle.label;"
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    onload = "Startup()"
+    buttons="accept,cancel"
+    ondialogaccept="return finishMap();"
+    ondialogcancel="return onCancel();">
+
+  <!-- Methods common to all editor dialogs -->
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js" />
+
+  <!-- Methods for Image Map only -->
+  <script type="application/x-javascript" src="chrome://editor/content/EdImageMap.js" />
+  <script type="application/x-javascript" src="chrome://editor/content/EdImageMapShapes.js" />
+
+  <broadcaster id="args" value=""/>
+
+  <keyset id="dialogKeys">
+
+    <key id="deletespot"   keycode="VK_DELETE"   oncommand="deleteElement(currentElement)" />
+    <key id="nudgeup"      keycode="VK_UP"       oncommand="nudge(event, 'up')" />
+    <key id="nudgeleft"    keycode="VK_LEFT"     oncommand="nudge(event, 'left')" />
+    <key id="nudgedown"    keycode="VK_DOWN"     oncommand="nudge(event, 'down')" />
+    <key id="nudgeright"   keycode="VK_RIGHT"    oncommand="nudge(event, 'right')" />
+    <key id="mapclearkb"    key="&clear.accesskey;" command="Map:Clear"  modifiers="accel"/>
+    <key id="mapselectkb"   key="&selectall.accesskey;" command="Map:SelectAll"  modifiers="accel"/>
+    <key id="mapclosekb"    key="&close.accesskey;" command="Map:Close"  modifiers="accel"/>
+    <key id="mapcutkb"      key="&cut.accesskey;" command="Map:Cut"  modifiers="accel"/>
+    <key id="mapcopykb"     key="&copy.accesskey;" command="Map:Copy"  modifiers="accel"/>
+    <key id="mappastekb"    key="&paste.accesskey;" command="Map:Paste"  modifiers="accel"/>
+    <key id="mappropskb"    key="&props.accesskey;" command="Map:Props"  modifiers="accel"/>
+    <key id="maptbarkb"     key="&tbar.accesskey;" command="Map:ViewToolbar"  modifiers="accel"/>
+
+  </keyset>
+
+  <commandset id="commands">
+    <command id="Map:Clear" label="&clearCmd.label;" oncommand=""/>
+    <command id="Map:Close" label="&closeCmd.label;" oncommand="exitImageMap()"/>
+    <command id="Map:Copy" label="&copyCmd.label;" disabled="true" oncommand="cutCopy()"/>
+    <command id="Map:Cut" label="&cutCmd.label;" disabled="true" oncommand="cutCopy(true)"/>
+    <command id="Map:Paste" label="&pasteCmd.label;" disabled="true" oncommand="paste()"/>
+    <command id="Map:Props" label="&propsCmd.label;" oncommand="hotSpotProps(currentElement[0])"/>
+    <command id="Map:ViewToolbar" label="&showhideTbarCmd.label;" oncommand="hideToolbar()"/>
+    <command id="Map:Apercent" label="&apercentCmd.label;" checked="true" oncommand="zoom('', 1)"/>
+    <command id="Map:Bpercent" label="&bpercentCmd.label;" oncommand="zoom('', 2)"/>
+    <command id="Map:Cpercent" label="&cpercentCmd.label;" oncommand="zoom('', 4)"/>
+    <command id="Map:ZoomIn" label="&zoominCmd.label;" oncommand="zoom('in')"/>
+    <command id="Map:ZoomOut" label="&zoomoutCmd.label;" disabled="true" oncommand="zoom('out')"/>
+    <command id="Map:SelectAll" label="&selectallCmd.label;" oncommand="selectAll()"/>
+  </commandset>
+
+  <!-- Interim hack to transition from nsIXULWindowCallbacks/ShowWindowWithArgs -->
+  <broadcaster id="dialog.start" ready="false"/>
+  <observes element="dialog.start" attribute="ready" onchange="EditorStartup('html')"/>
+ 
+<toolbox class="toolbox-top" id="ImageMapToolbox">    
+<menubar persist="collapsed">
+  <!-- File menu -->
+  <menu id="mapfileMenu" label="&mapfileMenu.label;" accesskey="&mapfilemenu.accesskey;">
+    <menupopup>
+      <menuitem accesskey="&mapfileclear.accesskey;" key="mapclearkb" command="Map:Clear"/>
+      <menuitem accesskey="&mapfileclose.accesskey;" key="mapclosekb" command="Map:Close"/>
+    </menupopup>
+  </menu>
+
+  <!-- Edit menu -->
+  <menu id="mapeditMenu" label="&mapeditMenu.label;" accesskey="&mapeditmenu.accesskey;">
+    <menupopup>
+      <menuitem accesskey="&mapselectall.accesskey;" key="mapselectkb" command="Map:SelectAll"/>
+      <menuitem accesskey="&mapeditcut.accesskey;" key="mapcutkb" command="Map:Cut"/>
+      <menuitem accesskey="&mapeditcopy.accesskey;" key="mapcopykb" command="Map:Copy"/>
+      <menuitem accesskey="&mapeditpaste.accesskey;" key="mappastekb" command="Map:Paste"/>
+      <menuseparator/>
+      <menuitem accesskey="&mapeditprops.accesskey;" key="mappropskb" command="Map:Props"/>
+    </menupopup>
+  </menu>
+
+  <!-- View menu -->
+  <menu id="mapviewMenu" label="&mapviewMenu.label;" accesskey="&mapviewmenu.accesskey;">
+    <menupopup>
+      <menuitem id="view_hidetoolbar" accesskey="&mapviewtbar.accesskey;" key="maptbarkb" command="Map:ViewToolbar"/>
+      <menu id="mapscalingMenu" label="&mapviewScale.label;" accesskey="&mapviewscale.accesskey;">
+        <menupopup>
+          <menuitem accesskey="&zoomone.accesskey;" key="" command="Map:Apercent"/>
+          <menuitem accesskey="&zoomtwo.accesskey;" key="" command="Map:Bpercent"/>
+          <menuitem accesskey="&zoomthree.accesskey;" key="" command="Map:Cpercent"/>
+        </menupopup>
+      </menu>
+    </menupopup>
+  </menu>
+
+  <spacer flex="1"/>
+</menubar>
+
+
+<toolbar id="toolbar" class="toolbar-primary" persist="collapsed">
+  <button id="cutButton" class="button-toolbar-2 top" command="Map:Cut"/>
+  <button id="copyButton" class="button-toolbar-2 top" command="Map:Copy"/>
+  <button id="pasteButton" class="button-toolbar-2 top" command="Map:Paste"/>
+  <button id="zoomInButton" class="button-toolbar-2 top" command="Map:ZoomIn"/>
+  <button id="zoomOutButton" class="button-toolbar-2 top" command="Map:ZoomOut"/>
+  <spacer flex="1"/>
+</toolbar> 
+</toolbox>
+
+<hbox id="outer-box" flex="1">
+
+  <toolbar id="toolbox" orient="vertical">
+  <vbox>
+    <button id="pointerButton" class="tool" toggled="1" oncommand="changeTool(event, 'pointer');"/>
+    <button id="rectButton" class="tool" oncommand="changeTool(event, 'rect');"/>
+    <button id="cirButton" class="tool" oncommand="changeTool(event, 'cir');"/>
+    <button id="polyButton" class="tool" oncommand="changeTool(event, 'poly');"/>
+    <spacer flex="1"/>
+  </vbox>
+  </toolbar>
+
+  <!-- Content Area -->
+  <iframe id="content" src="EdImageMapPage.html" flex="1"
+    onmousedown="top.downMouse(event)"
+    onmouseup="top.upMouse(event)" 
+    onmousemove="top.moveMouse(event)"
+    onclick="top.clickMouse(event)" 
+  />
+
+</hbox>
+
+  <!-- from EdDialogOverlay -->
+  <!-- not sure if this is needed, but put it in just in case 
+  <hbox id="AdvancedEditButton"/> -->
+
+  <separator class="groove"/>
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdImageMapHotSpot.js
@@ -0,0 +1,97 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Dan Haddix
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// dialog initialization code
+function Startup()
+{
+  gDialog.urlInput = document.getElementById("urlInput");
+  gDialog.targetInput = document.getElementById("targetInput");
+  gDialog.altInput = document.getElementById("altInput");
+  gDialog.commonInput = document.getElementById("commonInput");
+
+  gDialog.hsHref = window.arguments[0].getAttribute("hsHref");
+  if (gDialog.hsHref != '')
+    gDialog.urlInput.value = gDialog.hsHref;
+
+  gDialog.hsAlt = window.arguments[0].getAttribute("hsAlt");
+  if (gDialog.hsAlt != '')
+    gDialog.altInput.value = gDialog.hsAlt;
+
+  gDialog.hsTarget = window.arguments[0].getAttribute("hsTarget");
+  if (gDialog.hsTarget != ''){
+    gDialog.targetInput.value = gDialog.hsTarget;
+    len = gDialog.commonInput.length;
+    for (i=0; i<len; i++){
+      if (gDialog.hsTarget == gDialog.commonInput.options[i].value)
+        gDialog.commonInput.options[i].selected = "true";
+    }
+  }
+
+  SetTextboxFocus(gDialog.urlInput);
+
+  SetWindowLocation();
+}
+
+function onAccept()
+{
+  dump(window.arguments[0].id+"\n");
+  window.arguments[0].setAttribute("hsHref", gDialog.urlInput.value);
+  window.arguments[0].setAttribute("hsAlt", gDialog.altInput.value);
+  window.arguments[0].setAttribute("hsTarget", gDialog.targetInput.value);
+
+  SaveWindowLocation();
+
+  window.close();
+}
+
+function changeTarget() {
+  gDialog.targetInput.value=gDialog.commonInput.value;
+}
+
+function chooseFile()
+{
+  // Get a local file, converted into URL format
+
+  fileName = GetLocalFileURL("html");
+  if (fileName && fileName != "") {
+    gDialog.urlInput.value = fileName;
+  }
+
+  // Put focus into the input field
+  SetTextboxFocus(gDialog.urlInput);
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdImageMapHotSpot.xul
@@ -0,0 +1,110 @@
+<?xml version="1.0"?>
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1999-2000
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -   Brian King
+   -   Dan Haddix
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+<?xml-stylesheet href="chrome://editor/skin/" type="text/css"?>
+
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?>
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorImageMapHotSpot.dtd">
+
+<dialog title="&windowTitle.label;"
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    onload = "Startup()"
+    ondialogaccept="return onAccept();"
+    ondialogcancel="return onCancel();">
+
+  <!-- Methods common to all editor dialogs -->
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdImageMapHotSpot.js"/>
+
+  <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+  <broadcaster id="args" value=""/>
+
+  <groupbox flex="1">
+    <caption id="titleInput" label="&link.label;"/>
+
+    <grid>
+      <columns><column/><column/><column/></columns>
+      <rows>
+        <row>
+          <label control="urlInput" value="&urlFieldset.label;"/>
+
+          <textbox id="urlInput" class="MinWidth20em" value="http://"/>
+
+          <button id="Browse" oncommand="chooseFile()" label="&browseButton.label;"/>
+        </row>
+      
+        <row>
+          <label control="altInput" value="&altFieldset.label;"/>
+
+          <textbox class="MinWidth20em" id="altInput"/>
+        </row>
+      </rows>
+    </grid>
+  </groupbox>
+
+  <groupbox flex="1">
+    <caption id="targetLabel" label="&targetFieldset.label;"/>
+    <grid>
+      <columns><column/><column/><column/></columns>
+      <rows>
+        <row>
+          <label control="targetInput" value="&target.label;"/>
+        </row>
+        <row>
+          <textbox class="MinWidth20em" id="targetInput"/>
+
+          <label id="commonLabel" value="&commonFieldset.label;"/>
+
+          <menulist id="commonInput" oncommand="changeTarget()">
+            <menupopup align="center">
+              <menuitem class="middle" value="" label="&none.value;"/>
+              <menuitem class="middle" value="_self" label="&same.value;"/>
+              <menuitem class="middle" value="_top" label="&whole.value;"/>
+              <menuitem class="middle" value="_blank" label="&new.value;"/>
+              <menuitem class="middle" value="_parent" label="&parent.value;"/>
+            </menupopup>
+          </menulist>
+
+        </row>
+      </rows>
+    </grid>
+  </groupbox>
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdImageMapPage.html
@@ -0,0 +1,45 @@
+<html>
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicatior Client code.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 2000
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -   Brian King
+   -   Dan Haddix
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either the GNU General Public License Version 2 or later (the "GPL"), or
+   - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the LGPL or the GPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+<head>
+<title></title>
+<link rel=StyleSheet href="chrome://editor/skin/EdImageMapPage.css" type="text/css">
+</head>
+<body>
+</body>
+</html>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdImageMapShapes.js
@@ -0,0 +1,887 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Dan Haddix (dan6992@hotmail.com)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var downTool = false;
+var dragActive = false;
+var dragObject = false;
+var startX = null;
+var startY = null;
+var endX = null;
+var endY = null;
+var downTool = false;
+var currentElement = [];
+var currentTool = "pointer";
+var currentRect = null;
+var currentCir = null;
+var currentPoly = null;
+var currentPoint = null;
+var rectCount = 1;
+var cirCount = 1;
+var polyCount = 1;
+var pointCount = 1;
+var xlock = false;
+var ylock = false;
+var resize = false;
+var currentZoom = 1;
+var clipBoard = [];
+
+function Rect(coords, href, target, alt, construct){
+  newRect = frameDoc.createElement("div");
+  newRect.setAttribute("class", "rect");
+  newRect.setAttribute("id", "rect"+rectCount++);
+  newRect.setAttribute("name", "hotspot");
+  currentRect = selectElement(frameDoc.body.appendChild(newRect));
+
+  // Add resize handles
+  // waiting for better drawing code
+  handletl = frameDoc.createElement("div");
+  handletl.setAttribute("class", "handletl");
+  handletl.setAttribute("name", "handle");
+  handletr = frameDoc.createElement("div");
+  handletr.setAttribute("class", "handletr");
+  handletr.setAttribute("name", "handle");
+  handlebl = frameDoc.createElement("div");
+  handlebl.setAttribute("class", "handlebl");
+  handlebl.setAttribute("name", "handle");
+  handlebr = frameDoc.createElement("div");
+  handlebr.setAttribute("class", "handlebr");
+  handlebr.setAttribute("name", "handle");
+  handlet = frameDoc.createElement("div");
+  handlet.setAttribute("class", "handlet");
+  handlet.setAttribute("name", "handle");
+  handlel = frameDoc.createElement("div");
+  handlel.setAttribute("class", "handlel");
+  handlel.setAttribute("name", "handle");
+  handler = frameDoc.createElement("div");
+  handler.setAttribute("class", "handler");
+  handler.setAttribute("name", "handle");
+  handleb = frameDoc.createElement("div");
+  handleb.setAttribute("class", "handleb");
+  handleb.setAttribute("name", "handle");
+  currentRect.appendChild(handletl);
+  currentRect.appendChild(handletr);
+  currentRect.appendChild(handlebl);
+  currentRect.appendChild(handlebr);
+  currentRect.appendChild(handlet);
+  currentRect.appendChild(handlel);
+  currentRect.appendChild(handler);
+  currentRect.appendChild(handleb);
+
+  if (!coords){
+    currentRect.style.left = startX+"px";
+    currentRect.style.top = startY+"px";
+    //currentRect.style.width = endX+"px";
+    //currentRect.style.height = endX+"px";
+  }
+  else{
+    var coordArray = coords.split(',');
+    currentRect.style.left = coordArray[0]+"px";
+    currentRect.style.top = coordArray[1]+"px";
+    currentRect.style.width = (parseInt(coordArray[2])-parseInt(coordArray[0]))+"px";
+    currentRect.style.height = (parseInt(coordArray[3])-parseInt(coordArray[1]))+"px";
+    if (href)
+      currentRect.setAttribute("hsHref", href);
+    if (target)
+      currentRect.setAttribute("hsTarget", target);
+    if (alt)
+      currentRect.setAttribute("hsAlt", alt);
+  }
+  if (construct)
+    currentRect = null;
+}
+
+function Circle(coords, href, target, alt, construct){
+  newCir = frameDoc.createElement("div");
+  newCir.setAttribute("class", "cir");
+  newCir.setAttribute("id", "cir"+cirCount++);
+  newCir.setAttribute("name", "hotspot");
+  currentCir = selectElement(frameDoc.body.appendChild(newCir));
+
+  // Add resize handles
+  handletl = frameDoc.createElement("div");
+  handletl.setAttribute("class", "handletl");
+  handletl.setAttribute("name", "handle");
+  handletr = frameDoc.createElement("div");
+  handletr.setAttribute("class", "handletr");
+  handletr.setAttribute("name", "handle");
+  handlebl = frameDoc.createElement("div");
+  handlebl.setAttribute("class", "handlebl");
+  handlebl.setAttribute("name", "handle");
+  handlebr = frameDoc.createElement("div");
+  handlebr.setAttribute("class", "handlebr");
+  handlebr.setAttribute("name", "handle");
+  currentCir.appendChild(handletl);
+  currentCir.appendChild(handletr);
+  currentCir.appendChild(handlebl);
+  currentCir.appendChild(handlebr);
+
+  if (!coords){
+    currentCir.style.left = startX+"px";
+    currentCir.style.top = startY+"px";
+    //currentCir.style.width = endX+"px";
+    //currentCir.style.height = endX+"px";
+  }
+  else{
+    var coordArray = coords.split(',');
+    radius = parseInt(coordArray[2]);
+    currentCir.style.left = (parseInt(coordArray[0])-radius)+"px";
+    currentCir.style.top = (parseInt(coordArray[1])-radius)+"px";
+    currentCir.style.width = (radius*2)+"px";
+    currentCir.style.height = (radius*2)+"px";
+    if (href)
+      currentCir.setAttribute("hsHref", href);
+    if (target)
+      currentCir.setAttribute("hsTarget", target);
+    if (alt)
+      currentCir.setAttribute("hsAlt", alt);
+  }
+  if (construct)
+    currentCir = null;
+}
+
+function Poly(coords, href, target, alt, construct){
+  dump('Poly Called\n');
+  newPoly = frameDoc.createElement("div");
+  newPoly.setAttribute("class", "poly");
+  newPoly.setAttribute("id", "poly"+polyCount++);
+  newPoly.setAttribute("name", "hotspot");
+  currentPoly = selectElement(frameDoc.body.appendChild(newPoly));
+  if (currentZoom > 1){
+    currentPoly.style.width = imageEl.offsetWidth+"px";
+    currentPoly.style.height = imageEl.offsetHeight+"px";
+  }
+  if (!coords){
+    addPoint(null, startX, startY, true);
+    //currentPoly.onclick = addPoint;
+    currentPoly.style.cursor = "crosshair";
+  }
+  else{
+    var coordArray = coords.split(',');
+    var len = coordArray.length;
+    for (i=0; i<len; i++){
+      addPoint(null, coordArray[i], coordArray[i+1]);
+      i++;
+    }
+    if (href)
+      currentPoly.setAttribute("hsHref", href);
+    if (target)
+      currentPoly.setAttribute("hsTarget", target);
+    if (alt)
+      currentPoly.setAttribute("hsAlt", alt);
+    polyFinish(null, construct);
+  }
+}
+
+function addPoint(event, pointX, pointY, start){
+  if (event){
+    dump('addPoint Called with event\n');
+    pointX = event.clientX+window.frames[0].pageXOffset;
+    pointY = event.clientY+window.frames[0].pageYOffset;
+    event.stopPropagation();
+    if (event.detail == 2){
+      polyFinish();
+      return;
+    }
+  }
+  else
+    dump('addPoint Called\n');
+  newPoint = frameDoc.createElement("div");
+  newPoint.setAttribute("class", "point");
+  newPoint.setAttribute("id", "point"+pointCount++);
+  newPoint.style.left = pointX+"px";
+  newPoint.style.top = pointY+"px";
+  if (start){
+    newPoint.setAttribute("class", "pointStart");
+    newPoint.style.cursor = "pointer";
+    //newPoint.onclick = polyFinish;
+    //newPoint.addEventListener("click", polyFinish, false);
+  }
+  currentPoly.appendChild(newPoint);
+}
+
+function polyFinish(event, construct){
+  dump("polyfinish called\n");
+  var len = currentPoly.childNodes.length;
+  if (len >=3){
+    var polyLeft = 1000000;
+    var polyTop = 1000000;
+    var polyWidth = 0;
+    var polyHeight = 0;
+    for(p=0; p<len; p++){
+      var curEl = currentPoly.childNodes[p];
+      curEl.setAttribute("class", "point");
+      curEl.style.cursor = "default";
+      pointLeft = parseInt(curEl.style.left);
+      pointTop = parseInt(curEl.style.top);
+      polyLeft = Math.min(polyLeft, pointLeft);
+      polyTop = Math.min(polyTop, pointTop);
+      dump(polyLeft+"\n");
+    }
+    for(p=0; p<len; p++){
+      var curEl = currentPoly.childNodes[p];
+      curEl.style.left = (parseInt(curEl.style.left)-polyLeft)+"px";
+      curEl.style.top = (parseInt(curEl.style.top)-polyTop)+"px";
+    }
+    for(p=0; p<len; p++){
+      var curEl = currentPoly.childNodes[p];
+      polyWidth = Math.max(polyWidth, (parseInt(curEl.style.left)+3));
+      polyHeight = Math.max(polyHeight, (parseInt(curEl.style.top)+3));
+    }
+    if (parseInt(currentPoly.style.left) >= 0){
+      polyLeft += parseInt(currentPoly.style.left);
+      polyTop += parseInt(currentPoly.style.top);
+    }
+    currentPoly.style.left = polyLeft+"px";
+    currentPoly.style.top = polyTop+"px";
+    currentPoly.style.width = polyWidth+"px";
+    currentPoly.style.height = polyHeight+"px";
+    //currentPoly.childNodes[0].onclick = null;
+    //currentPoly.onclick = null;
+    currentPoly.style.cursor = "auto";
+    //currentPoly.childNodes[0].removeEventListener("click", polyFinish, false);
+    //currentPoly.removeEventListener("click", addPoint, true);
+    if (!construct)
+      hotSpotProps(currentPoly);
+  }
+  else
+    deleteElement(currentPoly);
+  if (event)
+    event.stopPropagation();
+
+  currentPoly = null;
+}
+
+function deleteElement(el){
+  if (el){
+    if (el.length){
+      var len = currentElement.length;
+      for(i=0; i<len; i++)
+        frameDoc.body.removeChild(currentElement[i]);
+    }
+    else
+      frameDoc.body.removeChild(el);
+  }
+}
+
+function selectAll(){
+  objList = frameDoc.getElementsByName("hotspot");
+  listLen = objList.length;
+  var objCount = 0;
+  for(a=0; a<listLen; a++){
+     selectElement(objList[a], objCount);
+     objCount++;
+  }
+}
+
+function selectElement(el, add){
+  if (add){
+    if (currentElement[0].getAttribute("class") != "poly"){
+      len = currentElement[0].childNodes.length;
+      for(i=0; i<len; i++)
+        currentElement[0].childNodes[i].style.visibility = "hidden";
+    }
+    currentElement.push(el);
+    document.getElementById("Map:Cut").setAttribute("disabled", "false");
+    document.getElementById("Map:Copy").setAttribute("disabled", "false");
+    return currentElement[currentElement.length-1];
+  }
+  else{
+    if (currentElement[0]){
+      if (currentElement[0].getAttribute("class") != "poly"){
+        len = currentElement[0].childNodes.length;
+        for(i=0; i<len; i++)
+          currentElement[0].childNodes[i].style.visibility = "hidden";
+      }
+    }
+    currentElement = null;
+    currentElement = [];
+    currentElement[0] = el;
+    if (el != null){
+    if (currentElement[0].getAttribute("class") != "poly"){
+      len = currentElement[0].childNodes.length;
+      for(i=0; i<len; i++)
+        currentElement[0].childNodes[i].style.visibility = "visible";
+    }
+      document.getElementById("Map:Cut").setAttribute("disabled", "false");
+      document.getElementById("Map:Copy").setAttribute("disabled", "false");
+    return currentElement[0];
+  }
+    else{
+      document.getElementById("Map:Cut").setAttribute("disabled", "true");
+      document.getElementById("Map:Copy").setAttribute("disabled", "true");
+    }
+  }
+}
+
+function deSelectElement(el){
+  var len = currentElement.length;
+  var j=0;
+  for(i=0; i<len; i++){
+    dump(j+"\n");
+    currentElement[j] = currentElement[i];
+    if (currentElement[i] != el)
+      j++;
+  }
+  currentElement.pop();
+  if (currentElement.length == 1){
+    selectElement(currentElement[0]);
+  }
+  if (currentElement.length >= 1){
+    document.getElementById("Map:Cut").setAttribute("disabled", "false");
+    document.getElementById("Map:Copy").setAttribute("disabled", "false");
+  }
+  else{
+    document.getElementById("Map:Cut").setAttribute("disabled", "true");
+    document.getElementById("Map:Copy").setAttribute("disabled", "true");
+  }
+}
+
+function marqueeSelect(){
+  marTop = parseInt(marquee.style.top);
+  marLeft = parseInt(marquee.style.left);
+  marRight = parseInt(marquee.style.width)+marLeft;
+  marBottom = parseInt(marquee.style.height)+marTop;
+  marquee.style.visibility = "hidden";
+  marquee.style.top = "-5px";
+  marquee.style.left = "-5px";
+  marquee.style.width = "1px";
+  marquee.style.height = "1px";
+  marquee = null;
+  objList = frameDoc.getElementsByName("hotspot");
+  listLen = objList.length;
+  var objCount = 0;
+  for(a=0; a<listLen; a++){
+    objTop = parseInt(objList[a].style.top);
+    objLeft = parseInt(objList[a].style.left);
+    objRight = parseInt(objList[a].style.width)+objLeft;
+    objBottom = parseInt(objList[a].style.height)+objTop;
+    if ((objTop >= marTop) && (objLeft >= marLeft) && (objBottom <= marBottom) && (objRight <= marRight)){
+       //objList[i].style.borderColor = "#ffff00";
+       selectElement(objList[a], objCount);
+       objCount++;
+    }
+  }
+}
+
+function upMouse(event){
+  if (currentTool != "poly"){
+    if (marquee){
+      marqueeSelect();
+    }
+    if (currentRect){
+      if (!resize)
+        hotSpotProps(currentRect);
+      else
+         resize = false;
+    }
+    else if (currentCir){
+      if (!resize)
+        hotSpotProps(currentCir);
+      else
+        resize = false;
+    }
+    else if (currentPoint)
+      polyFinish(null, true);
+      
+    currentRect = null;
+    currentCir = null;
+    currentPoint=null;
+    downTool = false;
+    dragActive = false;
+    dragObject = false;
+    xlock = false;
+    ylock = false;
+  }
+}
+
+function moveMouse(event){
+  if (downTool){
+    endX = event.clientX+window.frames[0].pageXOffset;
+    endY = event.clientY+window.frames[0].pageYOffset;
+
+    if (dragActive){
+      if (currentElement.length > 0){
+        if (currentCir){
+          radiusWidth = Math.abs((endX-startX));
+          radiusHeight = Math.abs((endY-startY));
+          circleRadius = Math.max(radiusWidth, radiusHeight);
+          currentCir.style.top = Math.max(startY-circleRadius, 0)+"px";
+          currentCir.style.left = Math.max(startX-circleRadius, 0)+"px";
+          currentCir.style.width = (circleRadius*2)+"px";
+          currentCir.style.height = (circleRadius*2)+"px";
+        }
+        else if (currentRect || marquee){
+          var rectObject = (currentRect)? currentRect : marquee;
+          if (!xlock){
+            if (endX > startX){
+              rectWidth = endX-startX;
+              rectObject.style.left = Math.max(startX, 0 )+"px";
+              rectObject.style.width = rectWidth+"px";
+            }
+            else{
+              rectWidth = startX-endX;
+              rectObject.style.left = Math.max(endX, 0)+"px";
+              rectObject.style.width = rectWidth+"px";
+            }
+          }
+          if (!ylock){
+            if (endY > startY){
+              rectHeight = endY-startY;
+              rectObject.style.top = startY+"px";
+              rectObject.style.height = rectHeight+"px";
+            }
+            else{
+              rectHeight = startY-endY;
+              rectObject.style.top = endY+"px";
+              rectObject.style.height = rectHeight+"px";
+            }
+          }
+        }
+      }
+    }
+    else{
+      if (currentTool == "rect"){
+        if ((((endX-startX) > 1) || ((endX-startX) < -1)) && (((endY-startY) > 1) || ((endY-startY) < -1))){
+          Rect();
+          dragActive = true;
+        }
+      }
+      if (currentTool == "cir"){
+        if ((((endX-startX) > 1) || ((endX-startX) < -1)) && (((endY-startY) > 1) || ((endY-startY) < -1))){
+          Circle();
+          dragActive = true;
+        }
+      }
+      if (currentTool == "pointer"){
+        if (dragObject){
+          var len = currentElement.length;
+          var maxX = false;
+          var maxY = false;
+          for(i=0; i<len; i++){
+            newX = Math.max(0, (endX-currentElement[i].startX));
+            newY = Math.max(0, (endY-currentElement[i].startY));
+            if (newX == 0)
+              maxX = true;
+            if (newY == 0)
+              maxY = true;
+          }
+          for(i=0; i<len; i++){
+            newX = Math.max(0, (endX-currentElement[i].startX));
+            newY = Math.max(0, (endY-currentElement[i].startY));
+            if ((newX > 0) && (maxX != true))
+              currentElement[i].style.left = newX+"px";
+            if ((newY >0) && (maxY != true))
+              currentElement[i].style.top = newY+"px";
+          }
+        }
+        else if (currentPoint){
+           endX = endX-parseInt(currentPoint.parentNode.style.left);
+           endY = endY-parseInt(currentPoint.parentNode.style.top);
+           newX = Math.max((0-parseInt(currentPoint.parentNode.style.left)), (endX-currentPoint.startX));
+           newY = Math.max((0-parseInt(currentPoint.parentNode.style.top)), (endY-currentPoint.startY));
+           currentPoint.style.left = newX+"px";
+           currentPoint.style.top = newY+"px";
+        }
+        else{
+          marquee = frameDoc.getElementById("marquee");
+          marquee.style.visibility = "visible";
+          dragActive = true;
+        }
+      }
+    }
+  }
+}
+
+
+function downMouse(event){
+  dump(event.target.parentNode.id+"\n");
+  if (event.button == 0){
+    if (currentTool != "poly"){
+      startX = event.clientX+window.frames[0].pageXOffset;
+      startY = event.clientY+window.frames[0].pageYOffset;
+      downTool = true;
+      if (currentTool == "pointer"){
+        if (event.target.getAttribute("name") == "hotspot"){
+          var el = event.target;
+          var isSelected = false;
+
+          if (event.target.getAttribute("cir") == "true")
+            el = event.target.parentNode;
+
+          if (event.shiftKey){
+            var len = currentElement.length;
+            var deselect = false;
+            for(i=0; i<len; i++){
+              if (currentElement[i] == el){
+                deSelectElement(el);
+                return;
+              }
+            }
+            selectElement(el, true);
+            isSelected = true; 
+          }
+          else{
+            var len = currentElement.length;
+            for(i=0; i<len; i++){
+              if (currentElement[i] == el)
+                isSelected = true;
+            }
+          }
+
+          if (isSelected){
+            var len = currentElement.length;
+            for(i=0; i<len; i++){
+              currentElement[i].startX = parseInt(event.clientX+window.frames[0].pageXOffset)-parseInt(currentElement[i].style.left);
+              currentElement[i].startY = parseInt(event.clientY+window.frames[0].pageYOffset)-parseInt(currentElement[i].style.top);
+            }
+          }
+          else{
+            curObj = selectElement(el);
+            curObj.startX = parseInt(event.clientX+window.frames[0].pageXOffset)-parseInt(curObj.style.left);
+            curObj.startY = parseInt(event.clientY+window.frames[0].pageYOffset)-parseInt(curObj.style.top);
+          }
+          dragObject = true;
+        }
+        else if (event.target.getAttribute("name") == "handle"){
+          dump("down on a handle\n");
+          resize = true;
+          el = event.target;
+          curObj = selectElement(el.parentNode);
+          if (curObj.className == "rect"){
+            currentRect = curObj;
+            switch (el.className){
+              case "handletl":
+                startX = parseInt(curObj.style.left)+parseInt(curObj.style.width);
+                startY = parseInt(curObj.style.top)+parseInt(curObj.style.height);
+                break;
+              case "handletr":
+                startX = parseInt(curObj.style.left);
+                startY = parseInt(curObj.style.top)+parseInt(curObj.style.height);
+                break;
+              case "handlebl":
+                startX = parseInt(curObj.style.left)+parseInt(curObj.style.width);
+                startY = parseInt(curObj.style.top);
+                break;
+              case "handlebr":
+                startX = parseInt(curObj.style.left);
+                startY = parseInt(curObj.style.top);
+                break;
+              case "handlet":
+                xlock = true;
+                startY = parseInt(curObj.style.top)+parseInt(curObj.style.height);
+                break;
+              case "handleb":
+                xlock = true;
+                startY = parseInt(curObj.style.top);
+                break;
+              case "handlel":
+                ylock = true;
+                startX = parseInt(curObj.style.left)+parseInt(curObj.style.width);
+                break;
+              case "handler":
+                ylock = true;
+                startX = parseInt(curObj.style.left);
+                break;
+              default:
+                return;
+            } 
+          }
+          else{
+            currentCir = curObj;
+            startX = parseInt(curObj.style.left)+(parseInt(curObj.style.width)/2);
+            startY = parseInt(curObj.style.top)+(parseInt(curObj.style.height)/2);
+          }
+        }
+        else if (event.target.getAttribute("class") == "point"){
+          dump("down on a point\n");
+          selectElement(event.target.parentNode);
+          currentPoint = event.target;
+          currentPoint.startX = parseInt(event.clientX+window.frames[0].pageXOffset)-(parseInt(currentPoint.style.left)+parseInt(currentPoint.parentNode.style.left));
+          currentPoint.startY = parseInt(event.clientY+window.frames[0].pageYOffset)-(parseInt(currentPoint.style.top)+parseInt(currentPoint.parentNode.style.top));
+          currentPoly = currentPoint.parentNode;
+        }
+        else{
+          dump(event.target+"\n");
+          selectElement(null);
+        }
+      }
+    }
+  }
+}
+
+function clickMouse(event){
+  if (event.button == 0){
+    dump("body clicked\n");
+    //alert(frameDoc.+'\n');
+    startX = event.clientX+window.frames[0].pageXOffset;
+    startY = event.clientY+window.frames[0].pageYOffset;
+    if (currentTool == "poly"){
+      if (event.target != currentPoly){
+        if (currentPoly != null){
+          if (event.target == currentPoly.childNodes[0]){
+            polyFinish();
+          }
+          else if (event.detail == 2){
+            polyFinish();
+          }
+        }
+        else{
+          Poly();
+        }
+      }
+      else{
+        addPoint(event);          
+      }
+    }
+  }
+}
+
+function changeTool(event, what){
+  if (!currentPoly){
+    for(i=0; i<4; i++){
+      buttonArray[i].setAttribute("toggled", 0);
+      if (event.target == buttonArray[i]){
+        buttonArray[i].setAttribute("toggled", 1);
+      }
+    }
+    currentTool = what;
+    if (currentTool != "pointer"){
+      frameDoc.getElementById("bgDiv").style.cursor = "crosshair";
+      frameDoc.body.style.cursor = "crosshair";
+    }
+    else{
+      frameDoc.getElementById("bgDiv").style.cursor = "default";
+      frameDoc.body.style.cursor = "default";
+    }
+
+    dump(what+" selected\n");
+  }
+  else {
+    for(i=0; i<4; i++){
+      if (event.target == buttonArray[i]){
+        buttonArray[i].setAttribute("toggled", 0);
+      }
+    }
+  }
+}
+
+function zoom(direction, ratio){
+  dump('zoom called; ratio='+ratio+'\n');
+  if (direction == "in")
+    ratio = currentZoom*2;
+  else if (direction == "out")
+    ratio = currentZoom/2;
+
+  if (ratio > 4 || ratio < 1 || ratio == currentZoom)
+    return;
+
+  if (ratio == 1){
+    document.getElementById('Map:ZoomIn').setAttribute('disabled', 'false');
+    document.getElementById('Map:ZoomOut').setAttribute('disabled', 'true');
+    document.getElementById('Map:Apercent').setAttribute('checked', 'true');
+    document.getElementById('Map:Bpercent').setAttribute('checked', 'false');
+    document.getElementById('Map:Cpercent').setAttribute('checked', 'false');
+  }
+  else if (ratio == 4){
+    document.getElementById('Map:ZoomIn').setAttribute('disabled', 'true');
+    document.getElementById('Map:ZoomOut').setAttribute('disabled', 'false');
+    document.getElementById('Map:Apercent').setAttribute('checked', 'false');
+    document.getElementById('Map:Bpercent').setAttribute('checked', 'false');
+    document.getElementById('Map:Cpercent').setAttribute('checked', 'true');
+  }
+  else {
+    document.getElementById('Map:ZoomIn').setAttribute('disabled', 'false');
+    document.getElementById('Map:ZoomOut').setAttribute('disabled', 'false');
+    document.getElementById('Map:Apercent').setAttribute('checked', 'false');
+    document.getElementById('Map:Bpercent').setAttribute('checked', 'true');
+    document.getElementById('Map:Cpercent').setAttribute('checked', 'false');
+  }
+
+  objList = frameDoc.getElementsByName("hotspot");
+  len = objList.length;
+  for(i=0; i<len; i++){
+    if (ratio > currentZoom){
+      objList[i].style.width = (parseInt(objList[i].style.width)*(ratio/currentZoom))+"px";
+      objList[i].style.height = (parseInt(objList[i].style.height)*(ratio/currentZoom))+"px";
+      objList[i].style.top = (parseInt(objList[i].style.top)*(ratio/currentZoom))+"px";
+      objList[i].style.left = (parseInt(objList[i].style.left)*(ratio/currentZoom))+"px";
+    }
+    else{
+      objList[i].style.width = (parseInt(objList[i].style.width)/(currentZoom/ratio))+"px";
+      objList[i].style.height = (parseInt(objList[i].style.height)/(currentZoom/ratio))+"px";
+      objList[i].style.top = (parseInt(objList[i].style.top)/(currentZoom/ratio))+"px";
+      objList[i].style.left = (parseInt(objList[i].style.left)/(currentZoom/ratio))+"px";
+    }
+    if (objList[i].getAttribute("class") == "poly"){
+      pointList = objList[i].childNodes;
+      plen = pointList.length;
+      dump('i='+i+'\n');
+      for(j=0; j<plen; j++){
+        dump('i='+i+'\n');
+        if (ratio > currentZoom){
+          pointList[j].style.top = (parseInt(pointList[j].style.top)*(ratio/currentZoom))+"px";
+          pointList[j].style.left = (parseInt(pointList[j].style.left)*(ratio/currentZoom))+"px";
+        }
+        else{
+          pointList[j].style.top = (parseInt(pointList[j].style.top)/(currentZoom/ratio))+"px";
+          pointList[j].style.left = (parseInt(pointList[j].style.left)/(currentZoom/ratio))+"px";
+        }
+      }
+      currentPoly = objList[i];
+      polyFinish(null, true);
+      currentPoly = null;
+    }
+    dump('i='+i+'\n');
+  }
+  
+  imgEl = frameDoc.getElementById("mainImg");
+  bgDiv = frameDoc.getElementById("bgDiv");
+  dump(imgEl.getAttribute("width")+'\n');
+  if (ratio > currentZoom){
+    imgEl.setAttribute("width", (parseInt(imgEl.offsetWidth)*(ratio/currentZoom)));
+    imgEl.setAttribute("height", (parseInt(imgEl.offsetHeight)*(ratio/currentZoom)));
+    bgDiv.style.width = imgEl.offsetWidth;
+    bgDiv.style.height = imgEl.offsetHeight;
+  }
+  else{
+    imgEl.setAttribute("width", (parseInt(imgEl.offsetWidth)/(currentZoom/ratio)));
+    imgEl.setAttribute("height", (parseInt(imgEl.offsetHeight)/(currentZoom/ratio)));
+    bgDiv.style.width = imgEl.offsetWidth;
+    bgDiv.style.height = imgEl.offsetHeight;
+  }
+  currentZoom = ratio;  
+}
+
+function cutCopy(cut){
+  len = currentElement.length;
+  if (len >= 1){
+    clipBoard = [];
+    for (i=0; i<len; i++){
+      el = currentElement[i];
+      if (el.className == 'rect'){
+        coords = parseInt(el.style.left)+","+parseInt(el.style.top)+","+(parseInt(el.style.left)+parseInt(el.style.width))+","+(parseInt(el.style.top)+parseInt(el.style.height));
+        href = el.getAttribute('hsHref');
+        target = el.getAttribute('hsTarget');
+        alt = el.getAttribute('hsAlt');
+        clipBoard[i] = 'Rect(\"'+coords+'\", \"'+href+'\", \"'+target+'\", \"'+alt+'\", true)';
+      }
+      else if (el.className == 'cir'){
+        radius = Math.floor(parseInt(el.style.width)/2);
+        coords = (parseInt(el.style.left)+radius)+","+(parseInt(el.style.top)+radius)+","+radius;
+        href = el.getAttribute('href');
+        target = el.getAttribute('hsTarget');
+        alt = el.getAttribute('hsAlt');
+        clipBoard[i] = 'Circle(\"'+coords+'\", \"'+href+'\", \"'+target+'\", \"'+alt+'\", true)';
+      }
+      else{
+        var coords = '';
+        var pointlen = el.childNodes.length;
+        for(j=0; j<pointlen; j++){
+          coords += (parseInt(el.style.left)+parseInt(el.childNodes[j].style.left))+","+(parseInt(el.style.top)+parseInt(el.childNodes[j].style.top))+",";
+        }
+        coords = coords.substring(0, (coords.length-1));
+        href = el.getAttribute('href');
+        target = el.getAttribute('hsTarget');
+        alt = el.getAttribute('hsAlt');
+        clipBoard[i] = 'Poly(\"'+coords+'\", \"'+href+'\", \"'+target+'\", \"'+alt+'\", true)';
+      }
+      if (cut){
+        deleteElement(el);
+      }
+    }
+    document.getElementById('Map:Paste').setAttribute('disabled', 'false');
+  }
+}
+
+function paste(){
+  len = clipBoard.length;
+  func = '';
+  for (i=0; i<len; i++){
+    func += clipBoard[i]+'\;';
+  }
+  eval(func);
+}
+
+  function nudge(event, dir){
+  /*prevent scrolling
+  event.stopPropagation(); 
+  event.preventDefault();*/
+
+  len = currentElement.length;
+  amount = 1;
+  if (event.shiftKey)
+    amount = 5;
+
+  
+  boundRectTop = 1000000;
+  boundRectLeft = 1000000;
+  for (i=0; i<len; i++){
+    curTop = parseInt(currentElement[i].style.top);
+    curLeft = parseInt(currentElement[i].style.left);
+    if (curTop < boundRectTop)
+      boundRectTop = curTop;
+    if (curLeft < boundRectLeft)
+      boundRectLeft = curLeft;
+  }
+
+  for (i=0; i<len; i++){
+    if (dir == "up"){
+      curTop = parseInt(currentElement[i].style.top);
+      if (boundRectTop >= amount)
+        currentElement[i].style.top = (curTop-amount) + "px";
+      else
+        currentElement[i].style.top = (curTop-boundRectTop) + "px";
+    }
+    else if (dir == "left"){
+      curLeft = parseInt(currentElement[i].style.left);
+      if (boundRectLeft >= amount)
+        currentElement[i].style.left = (curLeft-amount) + "px";
+      else
+        currentElement[i].style.left = (curLeft-boundRectLeft) + "px";
+    }
+    else if (dir == "down"){
+      curTop = parseInt(currentElement[i].style.top);
+      currentElement[i].style.top = (curTop+amount) + "px";
+    }
+    else if (dir == "right"){
+      curLeft = parseInt(currentElement[i].style.left);
+      currentElement[i].style.left = (curLeft+amount) + "px";
+    }
+  }
+}
+  
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdImageOverlay.js
@@ -0,0 +1,653 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Editor Image Properties Overlay.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Pete Collins
+ *   Brian King
+ *   Ben Goodger
+ *   Neil Rashbrook <neil@parkwaycc.co.uk> (Separated from EdImageProps.js)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ Note: We encourage non-empty alt text for images inserted into a page. 
+ When there's no alt text, we always write 'alt=""' as the attribute, since "alt" is a required attribute.
+ We allow users to not have alt text by checking a "Don't use alterate text" radio button,
+ and we don't accept spaces as valid alt text. A space used to be required to avoid the error message
+ if user didn't enter alt text, but is unnecessary now that we no longer annoy the user 
+ with the error dialog if alt="" is present on an img element.
+ We trim all spaces at the beginning and end of user's alt text
+*/
+
+var gInsertNewImage = true;
+var gInsertNewIMap = true;
+var gDoAltTextError = false;
+var gConstrainOn = false;
+// Note used in current version, but these are set correctly
+//  and could be used to reset width and height used for constrain ratio
+var gConstrainWidth  = 0;
+var gConstrainHeight = 0;
+var imageElement;
+var gImageMap = 0;
+var gCanRemoveImageMap = false;
+var gRemoveImageMap = false;
+var gImageMapDisabled = false;
+var gActualWidth = "";
+var gActualHeight = "";
+var gOriginalSrc = "";
+var gHaveDocumentUrl = false;
+var gTimerID;
+var gValidateTab;
+
+// These must correspond to values in EditorDialog.css for each theme
+// (unfortunately, setting "style" attribute here doesn't work!)
+var gPreviewImageWidth = 80;
+var gPreviewImageHeight = 50;
+
+// dialog initialization code
+
+function ImageStartup()
+{
+  gDialog.tabBox            = document.getElementById( "TabBox" );
+  gDialog.tabLocation       = document.getElementById( "imageLocationTab" );
+  gDialog.tabDimensions     = document.getElementById( "imageDimensionsTab" );
+  gDialog.tabBorder         = document.getElementById( "imageBorderTab" );
+  gDialog.srcInput          = document.getElementById( "srcInput" );
+  gDialog.titleInput        = document.getElementById( "titleInput" );
+  gDialog.altTextInput      = document.getElementById( "altTextInput" );
+  gDialog.altTextRadioGroup = document.getElementById( "altTextRadioGroup" );
+  gDialog.altTextRadio      = document.getElementById( "altTextRadio" );
+  gDialog.noAltTextRadio    = document.getElementById( "noAltTextRadio" );
+  gDialog.customSizeRadio   = document.getElementById( "customSizeRadio" );
+  gDialog.actualSizeRadio   = document.getElementById( "actualSizeRadio" );
+  gDialog.constrainCheckbox = document.getElementById( "constrainCheckbox" );
+  gDialog.widthInput        = document.getElementById( "widthInput" );
+  gDialog.heightInput       = document.getElementById( "heightInput" );
+  gDialog.widthUnitsMenulist   = document.getElementById( "widthUnitsMenulist" );
+  gDialog.heightUnitsMenulist  = document.getElementById( "heightUnitsMenulist" );
+  gDialog.imagelrInput      = document.getElementById( "imageleftrightInput" );
+  gDialog.imagetbInput      = document.getElementById( "imagetopbottomInput" );
+  gDialog.border            = document.getElementById( "border" );
+  gDialog.alignTypeSelect   = document.getElementById( "alignTypeSelect" );
+  gDialog.ImageHolder       = document.getElementById( "preview-image-holder" );
+  gDialog.PreviewWidth      = document.getElementById( "PreviewWidth" );
+  gDialog.PreviewHeight     = document.getElementById( "PreviewHeight" );
+  gDialog.PreviewSize       = document.getElementById( "PreviewSize" );
+  gDialog.PreviewImage      = null;
+  gDialog.OkButton          = document.documentElement.getButton("accept");
+}
+
+// Set dialog widgets with attribute data
+// We get them from globalElement copy so this can be used
+//   by AdvancedEdit(), which is shared by all property dialogs
+function InitImage()
+{
+  // Set the controls to the image's attributes
+  gDialog.srcInput.value = globalElement.getAttribute("src");
+
+  // Set "Relativize" checkbox according to current URL state
+  SetRelativeCheckbox();
+
+  // Force loading of image from its source and show preview image
+  LoadPreviewImage();
+
+  if (globalElement.hasAttribute("title"))
+    gDialog.titleInput.value = globalElement.getAttribute("title");
+
+  var hasAltText = globalElement.hasAttribute("alt");
+  var altText;
+  if (hasAltText)
+  {
+    altText = globalElement.getAttribute("alt");
+    gDialog.altTextInput.value = altText;
+  }
+
+  // Initialize altText widgets during dialog startup 
+  //   or if user enterred altText in Advanced Edit dialog
+  //  (this preserves "Don't use alt text" radio button state)
+  if (!gDialog.altTextRadioGroup.selectedItem || altText)
+  {
+    if (gInsertNewImage || !hasAltText || (hasAltText && gDialog.altTextInput.value))
+    {
+      SetAltTextDisabled(false);
+      gDialog.altTextRadioGroup.selectedItem = gDialog.altTextRadio;
+    }
+    else
+    {
+      SetAltTextDisabled(true);
+      gDialog.altTextRadioGroup.selectedItem = gDialog.noAltTextRadio;
+    }
+  }
+
+  // setup the height and width widgets
+  var width = InitPixelOrPercentMenulist(globalElement,
+                    gInsertNewImage ? null : imageElement,
+                    "width", "widthUnitsMenulist", gPixel);
+  var height = InitPixelOrPercentMenulist(globalElement,
+                    gInsertNewImage ? null : imageElement,
+                    "height", "heightUnitsMenulist", gPixel);
+
+  // Set actual radio button if both set values are the same as actual
+  SetSizeWidgets(width, height);
+
+  gDialog.widthInput.value  = gConstrainWidth = width ? width : (gActualWidth ? gActualWidth : "");
+  gDialog.heightInput.value = gConstrainHeight = height ? height : (gActualHeight ? gActualHeight : "");
+
+  // set spacing editfields
+  gDialog.imagelrInput.value = globalElement.getAttribute("hspace");
+  gDialog.imagetbInput.value = globalElement.getAttribute("vspace");
+
+  // dialog.border.value       = globalElement.getAttribute("border");
+  var bv = GetHTMLOrCSSStyleValue(globalElement, "border", "border-top-width");
+  if (/px/.test(bv))
+  {
+    // Strip out the px
+    bv = RegExp.leftContext;
+  }
+  else if (bv == "thin")
+  {
+    bv = "1";
+  }
+  else if (bv == "medium")
+  {
+    bv = "3";
+  }
+  else if (bv == "thick")
+  {
+    bv = "5";
+  }
+  gDialog.border.value = bv;
+
+  // Get alignment setting
+  var align = globalElement.getAttribute("align");
+  if (align)
+    align = align.toLowerCase();
+
+  var imgClass;
+  var textID;
+
+  switch ( align )
+  {
+    case "top":
+    case "middle":
+    case "right":
+    case "left":
+      gDialog.alignTypeSelect.value = align;
+      break;
+    default:  // Default or "bottom"
+      gDialog.alignTypeSelect.value = "bottom";
+  }
+
+  // Get image map for image
+  gImageMap = GetImageMap();
+
+  doOverallEnabling();
+  doDimensionEnabling();
+}
+
+function  SetSizeWidgets(width, height)
+{
+  if (!(width || height) || (gActualWidth && gActualHeight && width == gActualWidth && height == gActualHeight))
+    gDialog.actualSizeRadio.radioGroup.selectedItem = gDialog.actualSizeRadio;
+
+  if (!gDialog.actualSizeRadio.selected)
+  {
+    gDialog.actualSizeRadio.radioGroup.selectedItem = gDialog.customSizeRadio;
+
+    // Decide if user's sizes are in the same ratio as actual sizes
+    if (gActualWidth && gActualHeight)
+    {
+      if (gActualWidth > gActualHeight)
+        gDialog.constrainCheckbox.checked = (Math.round(gActualHeight * width / gActualWidth) == height);
+      else
+        gDialog.constrainCheckbox.checked = (Math.round(gActualWidth * height / gActualHeight) == width);
+    }
+  }
+}
+
+// Disable alt text input when "Don't use alt" radio is checked
+function SetAltTextDisabled(disable)
+{
+  gDialog.altTextInput.disabled = disable;
+}
+
+function GetImageMap()
+{
+  var usemap = globalElement.getAttribute("usemap");
+  if (usemap)
+  {
+    gCanRemoveImageMap = true;
+    var mapname = usemap.substring(1, usemap.length);
+    var mapCollection;
+    try {
+      mapCollection = GetCurrentEditor().document.getElementsByName(mapname);
+    } catch (e) {}
+    if (mapCollection && mapCollection[0] != null)
+    {
+      gInsertNewIMap = false;
+      return mapCollection[0];
+    }
+  }
+  else
+  {
+    gCanRemoveImageMap = false;
+  }
+
+  gInsertNewIMap = true;
+  return null;
+}
+
+function chooseFile()
+{
+  if (gTimerID)
+    clearTimeout(gTimerID);
+  // Get a local file, converted into URL format
+  var fileName = GetLocalFileURL("img");
+  if (fileName)
+  {
+    // Always try to relativize local file URLs
+    if (gHaveDocumentUrl)
+      fileName = MakeRelativeUrl(fileName);
+
+    gDialog.srcInput.value = fileName;
+
+    SetRelativeCheckbox();
+    doOverallEnabling();
+  }
+  LoadPreviewImage();
+
+  // Put focus into the input field
+  SetTextboxFocus(gDialog.srcInput);
+}
+
+function PreviewImageLoaded()
+{
+  if (gDialog.PreviewImage)
+  {
+    // Image loading has completed -- we can get actual width
+    gActualWidth  = gDialog.PreviewImage.naturalWidth;
+    gActualHeight = gDialog.PreviewImage.naturalHeight;
+
+    if (gActualWidth && gActualHeight)
+    {
+      // Use actual size or scale to fit preview if either dimension is too large
+      var width = gActualWidth;
+      var height = gActualHeight;
+      if (gActualWidth > gPreviewImageWidth)
+      {
+          width = gPreviewImageWidth;
+          height = gActualHeight * (gPreviewImageWidth / gActualWidth);
+      }
+      if (height > gPreviewImageHeight)
+      {
+        height = gPreviewImageHeight;
+        width = gActualWidth * (gPreviewImageHeight / gActualHeight);
+      }
+      gDialog.PreviewImage.width = width;
+      gDialog.PreviewImage.height = height;
+
+      gDialog.PreviewWidth.setAttribute("value", gActualWidth);
+      gDialog.PreviewHeight.setAttribute("value", gActualHeight);
+
+      gDialog.PreviewSize.collapsed = false;
+      gDialog.ImageHolder.collapsed = false;
+
+      SetSizeWidgets(gDialog.widthInput.value, gDialog.heightInput.value);
+    }
+
+    if (gDialog.actualSizeRadio.selected)
+      SetActualSize();
+  }
+}
+
+function LoadPreviewImage()
+{
+  gDialog.PreviewSize.collapsed = true;
+  // XXXbz workaround for bug 265416 / bug 266284
+  gDialog.ImageHolder.collapsed = true;
+
+  var imageSrc = TrimString(gDialog.srcInput.value);
+  if (!imageSrc)
+    return;
+
+  try {
+    // Remove the image URL from image cache so it loads fresh
+    //  (if we don't do this, loads after the first will always use image cache
+    //   and we won't see image edit changes or be able to get actual width and height)
+    
+    var IOService = GetIOService();
+    if (IOService)
+    {
+      // We must have an absolute URL to preview it or remove it from the cache
+      imageSrc = MakeAbsoluteUrl(imageSrc);
+
+      if (GetScheme(imageSrc))
+      {
+        var uri = IOService.newURI(imageSrc, null, null);
+        if (uri)
+        {
+          var imgCacheService = Components.classes["@mozilla.org/image/cache;1"].getService();
+          var imgCache = imgCacheService.QueryInterface(Components.interfaces.imgICache);
+
+          // This returns error if image wasn't in the cache; ignore that
+          imgCache.removeEntry(uri);
+        }
+      }
+    }
+  } catch(e) {}
+
+  if (gDialog.PreviewImage)
+    removeEventListener("load", PreviewImageLoaded, true);
+
+  if (gDialog.ImageHolder.firstChild)
+    gDialog.ImageHolder.removeChild(gDialog.ImageHolder.firstChild);
+    
+  gDialog.PreviewImage = document.createElementNS("http://www.w3.org/1999/xhtml", "html:img");
+  if (gDialog.PreviewImage)
+  {
+    // set the src before appending to the document -- see bug 198435 for why
+    // this is needed.
+    // XXXbz that bug is long-since fixed.  Is this still needed?
+    gDialog.PreviewImage.addEventListener("load", PreviewImageLoaded, true);
+    gDialog.PreviewImage.src = imageSrc;
+    gDialog.ImageHolder.appendChild(gDialog.PreviewImage);
+  }
+}
+
+function SetActualSize()
+{
+  gDialog.widthInput.value = gActualWidth ? gActualWidth : "";
+  gDialog.widthUnitsMenulist.selectedIndex = 0;
+  gDialog.heightInput.value = gActualHeight ? gActualHeight : "";
+  gDialog.heightUnitsMenulist.selectedIndex = 0;
+  doDimensionEnabling();
+}
+
+function ChangeImageSrc()
+{
+  if (gTimerID)
+    clearTimeout(gTimerID);
+
+  gTimerID = setTimeout("LoadPreviewImage()", 800);
+
+  SetRelativeCheckbox();
+  doOverallEnabling();
+}
+
+function doDimensionEnabling()
+{
+  // Enabled only if "Custom" is selected
+  var enable = (gDialog.customSizeRadio.selected);
+
+  // BUG 74145: After input field is disabled,
+  //   setting it enabled causes blinking caret to appear
+  //   even though focus isn't set to it.
+  SetElementEnabledById( "heightInput", enable );
+  SetElementEnabledById( "heightLabel", enable );
+  SetElementEnabledById( "heightUnitsMenulist", enable );
+
+  SetElementEnabledById( "widthInput", enable );
+  SetElementEnabledById( "widthLabel", enable);
+  SetElementEnabledById( "widthUnitsMenulist", enable );
+
+  var constrainEnable = enable
+         && ( gDialog.widthUnitsMenulist.selectedIndex == 0 )
+         && ( gDialog.heightUnitsMenulist.selectedIndex == 0 );
+
+  SetElementEnabledById( "constrainCheckbox", constrainEnable );
+}
+
+function doOverallEnabling()
+{
+  var enabled = TrimString(gDialog.srcInput.value) != "";
+
+  SetElementEnabled(gDialog.OkButton, enabled);
+  SetElementEnabledById("AdvancedEditButton1", enabled);
+  SetElementEnabledById("imagemapLabel", enabled);
+
+  //TODO: Restore when Image Map editor is finished
+  //SetElementEnabledById("editImageMap", enabled);
+  SetElementEnabledById("removeImageMap", gCanRemoveImageMap);
+}
+
+function ToggleConstrain()
+{
+  // If just turned on, save the current width and height as basis for constrain ratio
+  // Thus clicking on/off lets user say "Use these values as aspect ration"
+  if (gDialog.constrainCheckbox.checked && !gDialog.constrainCheckbox.disabled
+     && (gDialog.widthUnitsMenulist.selectedIndex == 0)
+     && (gDialog.heightUnitsMenulist.selectedIndex == 0))
+  {
+    gConstrainWidth = Number(TrimString(gDialog.widthInput.value));
+    gConstrainHeight = Number(TrimString(gDialog.heightInput.value));
+  }
+}
+
+function constrainProportions( srcID, destID )
+{
+  var srcElement = document.getElementById(srcID);
+  if (!srcElement)
+    return;
+
+  var destElement = document.getElementById(destID);
+  if (!destElement)
+    return;
+
+  // always force an integer (whether we are constraining or not)
+  forceInteger(srcID);
+
+  if (!gActualWidth || !gActualHeight ||
+      !(gDialog.constrainCheckbox.checked && !gDialog.constrainCheckbox.disabled))
+    return;
+
+  // double-check that neither width nor height is in percent mode; bail if so!
+  if ( (gDialog.widthUnitsMenulist.selectedIndex != 0)
+     || (gDialog.heightUnitsMenulist.selectedIndex != 0) )
+    return;
+
+  // This always uses the actual width and height ratios
+  // which is kind of funky if you change one number without the constrain
+  // and then turn constrain on and change a number
+  // I prefer the old strategy (below) but I can see some merit to this solution
+  if (srcID == "widthInput")
+    destElement.value = Math.round( srcElement.value * gActualHeight / gActualWidth );
+  else
+    destElement.value = Math.round( srcElement.value * gActualWidth / gActualHeight );
+
+/*
+  // With this strategy, the width and height ratio
+  //   can be reset to whatever the user entered.
+  if (srcID == "widthInput")
+    destElement.value = Math.round( srcElement.value * gConstrainHeight / gConstrainWidth );
+  else
+    destElement.value = Math.round( srcElement.value * gConstrainWidth / gConstrainHeight );
+*/
+}
+
+function editImageMap()
+{
+  // Create an imagemap for image map editor
+  if (gInsertNewIMap)
+  {
+    try {
+      gImageMap = GetCurrentEditor().createElementWithDefaults("map");
+    } catch (e) {}
+  }
+
+  // Note: We no longer pass in a copy of the global ImageMap. ImageMap editor should create a copy and manage onOk and onCancel behavior
+  window.openDialog("chrome://editor/content/EdImageMap.xul", "_blank", "chrome,close,titlebar,modal", globalElement, gImageMap);
+}
+
+function removeImageMap()
+{
+  gRemoveImageMap = true;
+  gCanRemoveImageMap = false;
+  SetElementEnabledById("removeImageMap", false);
+}
+
+function SwitchToValidatePanel()
+{
+  if (gDialog.tabBox && gValidateTab && gDialog.tabBox.selectedTab != gValidateTab)
+    gDialog.tabBox.selectedTab = gValidateTab;
+}
+
+// Get data from widgets, validate, and set for the global element
+//   accessible to AdvancedEdit() [in EdDialogCommon.js]
+function ValidateImage()
+{
+  var editor = GetCurrentEditor();
+  if (!editor)
+    return false;
+
+  gValidateTab = gDialog.tabLocation;
+  if (!gDialog.srcInput.value)
+  {
+    AlertWithTitle(null, GetString("MissingImageError"));
+    SwitchToValidatePanel();
+    gDialog.srcInput.focus();
+    return false;
+  }
+
+  // We must convert to "file:///" or "http://" format else image doesn't load!
+  var src = TrimString(gDialog.srcInput.value);
+  var checkbox = document.getElementById("MakeRelativeCheckbox");
+  try
+  {
+    if (checkbox && !checkbox.checked)
+    {
+      var URIFixup = Components.classes["@mozilla.org/docshell/urifixup;1"]
+                               .getService(Components.interfaces.nsIURIFixup);
+      src = URIFixup.createFixupURI(src, Components.interfaces.nsIURIFixup.FIXUP_FLAG_NONE).spec;
+    }
+  } catch (e) { }
+
+  globalElement.setAttribute("src", src);
+
+  var title = TrimString(gDialog.titleInput.value);
+  if (title)
+    globalElement.setAttribute("title", title);
+  else
+    globalElement.removeAttribute("title");
+
+  // Force user to enter Alt text only if "Alternate text" radio is checked
+  // Don't allow just spaces in alt text
+  var alt = "";
+  var useAlt = gDialog.altTextRadioGroup.selectedItem == gDialog.altTextRadio;
+  if (useAlt)
+    alt = TrimString(gDialog.altTextInput.value);
+
+  if (gDoAltTextError && useAlt && !alt)
+  {
+    AlertWithTitle(null, GetString("NoAltText"));
+    SwitchToValidatePanel();
+    gDialog.altTextInput.focus();
+    return false;
+  }
+  globalElement.setAttribute("alt", alt);
+
+  var width = "";
+  var height = "";
+
+  gValidateTab = gDialog.tabDimensions;
+  if (!gDialog.actualSizeRadio.selected)
+  {
+    // Get user values for width and height
+    width = ValidateNumber(gDialog.widthInput, gDialog.widthUnitsMenulist, 1, gMaxPixels, 
+                           globalElement, "width", false, true);
+    if (gValidationError)
+      return false;
+
+    height = ValidateNumber(gDialog.heightInput, gDialog.heightUnitsMenulist, 1, gMaxPixels, 
+                            globalElement, "height", false, true);
+    if (gValidationError)
+      return false;
+  }
+
+  // We always set the width and height attributes, even if same as actual.
+  //  This speeds up layout of pages since sizes are known before image is loaded
+  if (!width)
+    width = gActualWidth;
+  if (!height)
+    height = gActualHeight;
+
+  // Remove existing width and height only if source changed
+  //  and we couldn't obtain actual dimensions
+  var srcChanged = (src != gOriginalSrc);
+  if (width)
+    editor.setAttributeOrEquivalent(globalElement, "width", width, true);
+  else if (srcChanged)
+    editor.removeAttributeOrEquivalent(globalElement, "width", true);
+
+  if (height)
+    editor.setAttributeOrEquivalent(globalElement, "height", height, true);
+  else if (srcChanged) 
+    editor.removeAttributeOrEquivalent(globalElement, "height", true);
+
+  // spacing attributes
+  gValidateTab = gDialog.tabBorder;
+  ValidateNumber(gDialog.imagelrInput, null, 0, gMaxPixels, 
+                 globalElement, "hspace", false, true, true);
+  if (gValidationError)
+    return false;
+
+  ValidateNumber(gDialog.imagetbInput, null, 0, gMaxPixels, 
+                 globalElement, "vspace", false, true);
+  if (gValidationError)
+    return false;
+
+  // note this is deprecated and should be converted to stylesheets
+  ValidateNumber(gDialog.border, null, 0, gMaxPixels, 
+                 globalElement, "border", false, true);
+  if (gValidationError)
+    return false;
+
+  // Default or setting "bottom" means don't set the attribute
+  // Note that the attributes "left" and "right" are opposite
+  //  of what we use in the UI, which describes where the TEXT wraps,
+  //  not the image location (which is what the HTML describes)
+  switch ( gDialog.alignTypeSelect.value )
+  {
+    case "top":
+    case "middle":
+    case "right":
+    case "left":
+      editor.setAttributeOrEquivalent( globalElement, "align",
+                                       gDialog.alignTypeSelect.value , true);
+      break;
+    default:
+      try {
+        editor.removeAttributeOrEquivalent(globalElement, "align", true);
+      } catch (e) {}
+  }
+
+  return true;
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdImageOverlay.xul
@@ -0,0 +1,296 @@
+<?xml version="1.0"?>
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Editor Image Properties Overlay.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-2000
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -   Pete Collins
+   -   Brian King
+   -   Neil Rashbrook <neil@parkwaycc.co.uk> (Separated from EdImageProps.xul)
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!DOCTYPE overlay SYSTEM "chrome://editor/locale/EditorImageProperties.dtd">
+
+<overlay id="EdImageOverlay"
+     xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+  <script type="application/x-javascript" src="chrome://editor/content/EdImageOverlay.js"/>
+
+  <tab id="imageInputTab" label="&imageInputTab.label;"/>
+  <tab id="imageLocationTab" label="&imageLocationTab.label;"/>
+  <tab id="imageDimensionsTab" label="&imageDimensionsTab.label;"/>
+  <tab id="imageAppearanceTab" label="&imageAppearanceTab.label;"/>
+  <tab id="imageLinkTab" label="&imageLinkTab.label;"/>
+
+  <vbox id="imageLocation"> 
+    <spacer class="spacer"/>
+    <label control = "srcInput"
+      value = "&locationEditField.label;"
+      accesskey="&locationEditField.accessKey;"
+      tooltiptext="&locationEditField.tooltip;"
+      />
+    <textbox id="srcInput" oninput="ChangeImageSrc();" tabindex="1" class="uri-element"/>
+    <hbox id="MakeRelativeHbox">
+      <checkbox 
+        id  = "MakeRelativeCheckbox"
+        for = "srcInput"
+        tabindex="2"/>
+      <!-- mail compose will insert custom item here defined in mailComposeEditorOverlay.xul -->
+      <spacer flex="1"/>
+      <!-- from EdDialogOverlay.xul -->
+      <button id="ChooseFile"  tabindex="3"/>
+    </hbox>
+    <spacer class="spacer"/>
+    <radiogroup id="altTextRadioGroup" flex="1">
+      <grid>
+        <columns><column/><column flex="1"/></columns>
+        <rows>
+          <row align="center">
+            <label 
+              style   = "margin-left: 26px"
+              control = "titleInput"
+              accesskey = "&title.accessKey;"
+              value   ="&title.label;"
+              tooltiptext="&title.tooltip;"
+              for     = "titleInput"/>
+            <textbox flex="1"
+              id      = "titleInput"
+              class   = "MinWidth20em"
+              tooltiptext="&title.tooltip;"
+              tabindex="4"/>
+          </row>
+          <row align="center">
+            <radio id = "altTextRadio" 
+              label   = "&altText.label;"
+              accesskey = "&altText.accessKey;"
+              tooltiptext="&altTextEditField.tooltip;"
+              oncommand = "SetAltTextDisabled(false);"
+              tabindex="5"/>
+            <textbox flex="1"
+              id      = "altTextInput"
+              class   = "MinWidth20em"
+              tooltiptext="&altTextEditField.tooltip;"
+              oninput = "SetAltTextDisabled(false);"
+              tabindex="6"/>
+          </row>
+        </rows>
+      </grid>
+
+      <radio id = "noAltTextRadio" 
+        label   = "&noAltText.label;"
+        accesskey = "&noAltText.accessKey;"
+        oncommand = "SetAltTextDisabled(true);"/>
+    </radiogroup>
+  </vbox>
+
+  <groupbox id="imagePreview" orient="horizontal" flex="1">
+    <caption label="&previewBox.label;"/>
+    <hbox id="preview-image-box" align="center">
+      <spacer flex="1"/>
+      <description id="preview-image-holder"/>
+      <spacer flex="1"/>
+    </hbox>
+    <vbox id="PreviewSize" collapsed="true">
+      <spacer flex="1"/>
+      <label value="&actualSize.label;"/>
+      <hbox>
+        <label value="&widthEditField.label;"/>
+        <spacer flex="1"/>
+        <label id="PreviewWidth"/>
+      </hbox>
+      <hbox>
+        <label value="&heightEditField.label;"/>
+        <spacer flex="1"/>
+        <label id="PreviewHeight"/>
+      </hbox>
+      <spacer flex="1"/>
+    </vbox>
+  </groupbox>
+
+  <vbox id="imageDimensions" align="start">
+    <spacer class="spacer"/>
+    <hbox>
+      <radiogroup id="imgSizeGroup">
+        <radio
+          id      = "actualSizeRadio" 
+          label   = "&actualSizeRadio.label;"
+          accesskey = "&actualSizeRadio.accessKey;"
+          tooltiptext="&actualSizeRadio.tooltip;"
+          oncommand = "SetActualSize()"/>
+        <radio
+          id      = "customSizeRadio" 
+          label   = "&customSizeRadio.label;"
+          accesskey = "&customSizeRadio.accessKey;"
+          tooltiptext="&customSizeRadio.tooltip;"
+          oncommand = "doDimensionEnabling();" />
+      </radiogroup>
+      <spacer flex="1"/>
+      <vbox>
+        <spacer flex="1"/>
+        <checkbox id="constrainCheckbox" label="&constrainCheckbox.label;"
+             accesskey="&constrainCheckbox.accessKey;"
+             oncommand="ToggleConstrain()"
+             tooltiptext="&constrainCheckbox.tooltip;"/>
+      </vbox>
+      <spacer flex="1"/>
+    </hbox>
+    <spacer class="spacer"/>
+    <grid class="indent">
+      <columns><column/><column/><column flex="1"/></columns>
+      <rows>
+        <row align="center">
+          <label id    = "widthLabel"
+            control   = "widthInput"
+            accesskey = "&widthEditField.accessKey;"
+            value = "&widthEditField.label;" />
+          <textbox
+            id       = "widthInput" 
+            class    = "narrow"
+            oninput  = "constrainProportions(this.id, 'heightInput')"/>
+          <menulist id = "widthUnitsMenulist"
+            oncommand = "doDimensionEnabling();" />
+          <!-- contents are appended by JS -->
+        </row>
+        <row align="center">
+          <label id    = "heightLabel"
+            control   = "heightInput"
+            accesskey = "&heightEditField.accessKey;"
+            value = "&heightEditField.label;" />
+          <textbox
+            id       = "heightInput" 
+            class    = "narrow"
+            oninput  = "constrainProportions(this.id, 'widthInput')"/>
+          <menulist id = "heightUnitsMenulist"
+            oncommand = "doDimensionEnabling();" />
+          <!-- contents are appended by JS -->
+        </row>
+      </rows>          
+    </grid>
+    <spacer flex="1"/>
+  </vbox>
+
+  <hbox id="imageAppearance">
+    <groupbox>
+      <caption id="spacingLabel" label="&spacingBox.label;"/>
+      <grid>
+        <columns><column/><column/><column/></columns>
+        <rows>
+          <row align="center">
+            <label 
+              class = "align-right" 
+              id    = "leftrightLabel"
+              control = "imageleftrightInput"
+              accesskey = "&leftRightEditField.accessKey;"
+              value = "&leftRightEditField.label;"/>
+            <textbox
+              class     = "narrow"
+              id        = "imageleftrightInput" 
+              oninput   = "forceInteger(this.id)"/>
+            <label 
+              id    = "leftrighttypeLabel"
+              value = "&pixelsPopup.value;" />
+          </row>
+          <spacer class="spacer"/>
+          <row align="center">
+            <label 
+              class = "align-right" 
+              id    = "topbottomLabel"
+              control = "imagetopbottomInput"
+              accesskey = "&topBottomEditField.accessKey;"
+              value = "&topBottomEditField.label;"/>
+            <textbox
+              class     = "narrow"
+              id        = "imagetopbottomInput" 
+              oninput   = "forceInteger(this.id)"/>
+            <label
+              id    = "topbottomtypeLabel"
+              value = "&pixelsPopup.value;" />
+          </row>
+          <spacer class="spacer"/>
+          <row align="center">
+            <label class = "align-right" 
+              id    = "borderLabel"
+              control = "border"
+              accesskey = "&borderEditField.accessKey;"
+              value = "&borderEditField.label;"/>
+            <textbox
+              class     = "narrow"
+              id        = "border" 
+              oninput   = "forceInteger(this.id)"/>
+            <label 
+              id    = "bordertypeLabel"
+              value = "&pixelsPopup.value;" />
+          </row>
+        </rows>
+      </grid>
+    </groupbox>
+
+    <vbox>
+      <groupbox align="start">
+        <caption id="alignLabel" label="&alignment.label;"/>
+        <menulist id="alignTypeSelect" class="align-menu">
+          <menupopup>
+            <menuitem class="align-menu" value="top"    label="&topPopup.value;"/>
+            <menuitem class="align-menu" value="middle" label="&centerPopup.value;"/>
+            <menuitem class="align-menu" value="bottom" label="&bottomPopup.value;"/>
+            <!-- HTML attribute value is opposite of the button label on purpose -->
+            <menuitem class="align-menu" value="right"  label="&wrapLeftPopup.value;"/>
+            <menuitem class="align-menu" value="left"   label="&wrapRightPopup.value;"/>
+          </menupopup>
+        </menulist>
+      </groupbox>
+
+      <groupbox>
+        <caption id="imagemapLabel" label="&imagemapBox.label;"/>
+        <hbox equalsize="always">
+
+<!-- Hide Image Map Editor. Not ready for prime time yet
+        <button
+          id      = "editImageMap"
+          oncommand = "editImageMap()"
+          tooltiptext="&editImageMapButton.tooltip;"
+          label   = "&editImageMapButton.label;"
+          flex    = "1"/>
+-->
+        <button
+          id      = "removeImageMap"
+          oncommand = "removeImageMap()"
+          accesskey = "&removeImageMapButton.accessKey;"
+          label   = "&removeImageMapButton.label;"
+          flex    = "1"/>
+        <spacer flex="1"/><!-- remove when we restore Image Map Editor -->
+        </hbox>
+      </groupbox>
+    </vbox>
+  </hbox>
+
+</overlay>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdImageProps.js
@@ -0,0 +1,320 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Pete Collins
+ *   Brian King
+ *   Ben Goodger
+ *   Charles Manske (cmanske@netscape.com)
+ *   Neil Rashbrook (neil@parkwaycc.co.uk)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var gAnchorElement = null;
+var gOriginalHref = "";
+var gHNodeArray = {};
+
+// dialog initialization code
+
+function Startup()
+{
+  var editor = GetCurrentEditor();
+  if (!editor)
+  {
+    window.close();
+    return;
+  }
+
+  ImageStartup();
+  gDialog.hrefInput        = document.getElementById("hrefInput");
+  gDialog.makeRelativeLink = document.getElementById("MakeRelativeLink");
+  gDialog.showLinkBorder   = document.getElementById("showLinkBorder");
+  gDialog.linkTab          = document.getElementById("imageLinkTab");
+
+  // Get a single selected image element
+  var tagName = "img";
+  if ("arguments" in window && window.arguments[0])
+  {
+    imageElement = window.arguments[0];
+    // We've been called from form field propertes, so we can't insert a link
+    gDialog.linkTab.parentNode.removeChild(gDialog.linkTab);
+    gDialog.linkTab = null;
+  }
+  else
+  {
+    // First check for <input type="image">
+    try {
+      imageElement = editor.getSelectedElement("input");
+
+      if (!imageElement || imageElement.getAttribute("type") != "image") {
+        // Get a single selected image element
+        imageElement = editor.getSelectedElement(tagName);
+        if (imageElement)
+          gAnchorElement = editor.getElementOrParentByTagName("href", imageElement);
+      }
+    } catch (e) {}
+
+  }
+
+  if (imageElement)
+  {
+    // We found an element and don't need to insert one
+    if (imageElement.hasAttribute("src"))
+    {
+      gInsertNewImage = false;
+      gActualWidth  = imageElement.naturalWidth;
+      gActualHeight = imageElement.naturalHeight;
+    }
+  }
+  else
+  {
+    gInsertNewImage = true;
+
+    // We don't have an element selected,
+    //  so create one with default attributes
+    try {
+      imageElement = editor.createElementWithDefaults(tagName);
+    } catch(e) {}
+
+    if (!imageElement)
+    {
+      dump("Failed to get selected element or create a new one!\n");
+      window.close();
+      return;
+    }
+    try {
+      gAnchorElement = editor.getSelectedElement("href");
+    } catch (e) {}
+  }
+
+  // Make a copy to use for AdvancedEdit
+  globalElement = imageElement.cloneNode(false);
+
+  // We only need to test for this once per dialog load
+  gHaveDocumentUrl = GetDocumentBaseUrl();
+
+  InitDialog();
+  if (gAnchorElement)
+    gOriginalHref = gAnchorElement.getAttribute("href");
+  gDialog.hrefInput.value = gOriginalHref;
+
+  FillLinkMenulist(gDialog.hrefInput, gHNodeArray);
+  ChangeLinkLocation();
+
+  // Save initial source URL
+  gOriginalSrc = gDialog.srcInput.value;
+
+  // By default turn constrain on, but both width and height must be in pixels
+  gDialog.constrainCheckbox.checked =
+    gDialog.widthUnitsMenulist.selectedIndex == 0 &&
+    gDialog.heightUnitsMenulist.selectedIndex == 0;
+
+  // Start in "Link" tab if 2nd arguement is true
+  if (gDialog.linkTab && "arguments" in window && window.arguments[1])
+  {
+    document.getElementById("TabBox").selectedTab = gDialog.linkTab;
+    SetTextboxFocus(gDialog.hrefInput);
+  }
+  else
+    SetTextboxFocus(gDialog.srcInput);
+
+  SetWindowLocation();
+}
+
+// Set dialog widgets with attribute data
+// We get them from globalElement copy so this can be used
+//   by AdvancedEdit(), which is shared by all property dialogs
+function InitDialog()
+{
+  InitImage();
+  var border = TrimString(gDialog.border.value);
+  gDialog.showLinkBorder.checked = border != "" && border > 0;
+}
+
+function ChangeLinkLocation()
+{
+  SetRelativeCheckbox(gDialog.makeRelativeLink);
+  gDialog.showLinkBorder.disabled = !TrimString(gDialog.hrefInput.value);
+}
+
+function ToggleShowLinkBorder()
+{
+  if (gDialog.showLinkBorder.checked)
+  {
+    var border = TrimString(gDialog.border.value);
+    if (!border || border == "0")
+      gDialog.border.value = "2";
+  }
+  else
+  {
+    gDialog.border.value = "0";
+  }
+}
+
+// Get data from widgets, validate, and set for the global element
+//   accessible to AdvancedEdit() [in EdDialogCommon.js]
+function ValidateData()
+{
+  return ValidateImage();
+}
+
+function onAccept()
+{
+  // Use this now (default = false) so Advanced Edit button dialog doesn't trigger error message
+  gDoAltTextError = true;
+
+  if (ValidateData())
+  {
+    if ("arguments" in window && window.arguments[0])
+    {
+      SaveWindowLocation();
+      return true;
+    }
+
+    var editor = GetCurrentEditor();
+
+    editor.beginTransaction();
+
+    try
+    {
+      if (gRemoveImageMap)
+      {
+        globalElement.removeAttribute("usemap");
+        if (gImageMap)
+        {
+          editor.deleteNode(gImageMap);
+          gInsertNewIMap = true;
+          gImageMap = null;
+        }
+      }
+      else if (gImageMap)
+      {
+        // un-comment to see that inserting image maps does not work!
+        /*
+        gImageMap = editor.createElementWithDefaults("map");
+        gImageMap.setAttribute("name", "testing");
+        var testArea = editor.createElementWithDefaults("area");
+        testArea.setAttribute("shape", "circle");
+        testArea.setAttribute("coords", "86,102,52");
+        testArea.setAttribute("href", "test");
+        gImageMap.appendChild(testArea);
+        */
+
+        // Assign to map if there is one
+        var mapName = gImageMap.getAttribute("name");
+        if (mapName != "")
+        {
+          globalElement.setAttribute("usemap", ("#"+mapName));
+          if (globalElement.getAttribute("border") == "")
+            globalElement.setAttribute("border", 0);
+        }
+      }
+
+      // Create or remove the link as appropriate
+      var href = gDialog.hrefInput.value;
+      if (href != gOriginalHref)
+      {
+        if (href && !gInsertNewImage)
+          EditorSetTextProperty("a", "href", href);
+        else
+          EditorRemoveTextProperty("href", "");
+      }
+
+      // If inside a link, always write the 'border' attribute
+      if (href)
+      {
+        if (gDialog.showLinkBorder.checked)
+        {
+          // Use default = 2 if border attribute is empty
+          if (!globalElement.hasAttribute("border"))
+            globalElement.setAttribute("border", "2");
+        }
+        else
+          globalElement.setAttribute("border", "0");
+      }
+
+      if (gInsertNewImage)
+      {
+        if (href) {
+          var linkElement = editor.createElementWithDefaults("a");
+          linkElement.setAttribute("href", href);
+          linkElement.appendChild(imageElement);
+          editor.insertElementAtSelection(linkElement, true);
+        }
+        else
+          // 'true' means delete the selection before inserting
+          editor.insertElementAtSelection(imageElement, true);
+      }
+
+      // Check to see if the link was to a heading
+      // Do this last because it moves the caret (BAD!)
+      if (href in gHNodeArray)
+      {
+        var anchorNode = editor.createElementWithDefaults("a");
+        if (anchorNode)
+        {
+          anchorNode.name = href.substr(1);
+          // Remember to use editor method so it is undoable!
+          editor.insertNode(anchorNode, gHNodeArray[href], 0, false);
+        }
+      }
+      // All values are valid - copy to actual element in doc or
+      //   element we just inserted
+      editor.cloneAttributes(imageElement, globalElement);
+
+      // If document is empty, the map element won't insert,
+      //  so always insert the image first
+      if (gImageMap && gInsertNewIMap)
+      {
+        // Insert the ImageMap element at beginning of document
+        var body = editor.rootElement;
+        editor.setShouldTxnSetSelection(false);
+        editor.insertNode(gImageMap, body, 0);
+        editor.setShouldTxnSetSelection(true);
+      }
+    }
+    catch (e)
+    {
+      dump(e);
+    }
+
+    editor.endTransaction();
+
+    SaveWindowLocation();
+    return true;
+  }
+
+  gDoAltTextError = false;
+
+  return false;
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdImageProps.xul
@@ -0,0 +1,100 @@
+<?xml version="1.0"?>
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-2000
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -   Pete Collins
+   -   Brian King
+   -   Neil Rashbrook <neil@parkwaycc.co.uk>
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<?xul-overlay href="chrome://editor/content/EdImageOverlay.xul"?> 
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?> 
+<?xul-overlay href="chrome://global/content/globalOverlay.xul"?>
+<?xul-overlay href="chrome://communicator/content/utilityOverlay.xul"?> 
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorImageProperties.dtd">
+
+
+<!-- dialog containing a control requiring initial setup -->
+<dialog id="imageDlg" title="&windowTitle.label;"
+    xmlns ="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    onload = "Startup()"
+    buttons="accept,cancel"
+    ondialogaccept="return onAccept();"
+    ondialogcancel="return onCancel();">
+  
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdImageProps.js"/>
+  <script type="application/x-javascript" src="chrome://global/content/globalOverlay.js"/>
+
+  <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+  <broadcaster id="args" value=""/>
+
+  <tabbox id="TabBox">
+    <tabs flex="1">
+      <tab id="imageLocationTab"/>
+      <tab id="imageDimensionsTab"/>
+      <tab id="imageAppearanceTab"/>
+      <tab id="imageLinkTab"/>
+    </tabs>
+    <tabpanels>
+      <!-- panels overlayed from EdImageOverlay.xul -->
+      <vbox id="imageLocation"/>
+      <vbox id="imageDimensions"/>
+      <hbox id="imageAppearance"/>
+      <vbox>
+        <spacer class="spacer"/>
+        <vbox id="LinkLocationBox"/>
+        <spacer class="spacer"/>
+        <checkbox id="showLinkBorder"
+                  label="&showImageLinkBorder.label;"
+                  accesskey="&showImageLinkBorder.accessKey;"
+                  oncommand="ToggleShowLinkBorder();"/>
+      </vbox>
+    </tabpanels>
+  </tabbox>
+
+  <hbox align="end">
+    <groupbox id="imagePreview"/>
+
+    <!-- from EdDialogOverlay -->
+    <vbox id="AdvancedEdit"/>
+  </hbox>
+
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdInputImage.js
@@ -0,0 +1,211 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Input Tag Properties Dialog.
+ *
+ * The Initial Developer of the Original Code is
+ * Neil Rashbrook.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s): Neil Rashbrook <neil@parkwaycc.co.uk>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// dialog initialization code
+
+function Startup()
+{
+  var editor = GetCurrentEditor();
+  if (!editor)
+  {
+    window.close();
+    return;
+  }
+
+  gDialog = {
+    inputName:      document.getElementById( "InputName" ),
+    inputDisabled:  document.getElementById( "InputDisabled" ),
+    inputTabIndex:  document.getElementById( "InputTabIndex" )
+  };
+
+  ImageStartup();
+
+  // Get a single selected input element
+  var tagName = "input";
+  try {
+    imageElement = editor.getSelectedElement(tagName);
+  } catch (e) {}
+
+  if (imageElement)
+  {
+    // We found an element and don't need to insert one
+    gInsertNewImage = false;
+  }
+  else
+  {
+    gInsertNewImage = true;
+
+    // We don't have an element selected,
+    //  so create one with default attributes
+    try {
+      imageElement = editor.createElementWithDefaults(tagName);
+    } catch(e) {}
+
+    if (!imageElement )
+    {
+      dump("Failed to get selected element or create a new one!\n");
+      window.close();
+      return;
+    }
+    var imgElement;
+    try {
+      imgElement = editor.getSelectedElement("img");
+    } catch(e) {}
+
+    if (imgElement)
+    {
+      // We found an image element, convert it to an input type="image"
+      var attributes = ["src", "alt", "width", "height", "hspace", "vspace", "border", "align", "usemap", "ismap"];
+      for (i in attributes)
+        imageElement.setAttribute(attributes[i], imgElement.getAttribute(attributes[i]));
+    }
+  }
+
+  // Make a copy to use for AdvancedEdit
+  globalElement = imageElement.cloneNode(false);
+
+  // We only need to test for this once per dialog load
+  gHaveDocumentUrl = GetDocumentBaseUrl();
+
+  InitDialog();
+
+  // Save initial source URL
+  gOriginalSrc = gDialog.srcInput.value;
+
+  // By default turn constrain on, but both width and height must be in pixels
+  gDialog.constrainCheckbox.checked =
+    gDialog.widthUnitsMenulist.selectedIndex == 0 &&
+    gDialog.heightUnitsMenulist.selectedIndex == 0;
+
+  SetTextboxFocus(gDialog.inputName);
+
+  SetWindowLocation();
+}
+
+function InitDialog()
+{
+  InitImage();
+  gDialog.inputName.value = globalElement.getAttribute("name");
+  gDialog.inputDisabled.setAttribute("checked", globalElement.hasAttribute("disabled"));
+  gDialog.inputTabIndex.value = globalElement.getAttribute("tabindex");
+}
+
+function ValidateData()
+{
+  if (!ValidateImage())
+    return false;
+  if (gDialog.inputName.value)
+    globalElement.setAttribute("name", gDialog.inputName.value);
+  else
+    globalElement.removeAttribute("name");
+  if (gDialog.inputTabIndex.value)
+    globalElement.setAttribute("tabindex", gDialog.inputTabIndex.value);
+  else
+    globalElement.removeAttribute("tabindex");
+  if (gDialog.inputDisabled.checked)
+    globalElement.setAttribute("disabled", "");
+  else
+    globalElement.removeAttribute("disabled");
+  globalElement.setAttribute("type", "image");
+  return true;
+}
+
+function onAccept()
+{
+  // Show alt text error only once
+  // (we don't initialize doAltTextError=true
+  //  so Advanced edit button dialog doesn't trigger that error message)
+  // Use this now (default = false) so Advanced Edit button dialog doesn't trigger error message
+  gDoAltTextError = true;
+
+  if (ValidateData())
+  {
+
+    var editor = GetCurrentEditor();
+    editor.beginTransaction();
+
+    try {
+      if (gRemoveImageMap)
+      {
+        globalElement.removeAttribute("usemap");
+        if (gImageMap)
+        {
+          editor.deleteNode(gImageMap);
+          gInsertNewIMap = true;
+          gImageMap = null;
+        }
+      }
+      else if (gImageMap)
+      {
+        // Assign to map if there is one
+        var mapName = gImageMap.getAttribute("name");
+        if (mapName != "")
+        {
+          globalElement.setAttribute("usemap", ("#"+mapName));
+          if (globalElement.getAttribute("border") == "")
+            globalElement.setAttribute("border", 0);
+        }
+      }
+
+      if (gInsertNewImage)
+      {
+        // 'true' means delete the selection before inserting
+        // in case were are converting an image to an input type="image"
+        editor.insertElementAtSelection(imageElement, true);
+      }
+      editor.cloneAttributes(imageElement, globalElement);
+
+      // If document is empty, the map element won't insert,
+      //  so always insert the image element first
+      if (gImageMap && gInsertNewIMap)
+      {
+        // Insert the ImageMap element at beginning of document
+        var body = editor.rootElement;
+        editor.setShouldTxnSetSelection(false);
+        editor.insertNode(gImageMap, body, 0);
+        editor.setShouldTxnSetSelection(true);
+      }
+    } catch (e) {}
+
+    editor.endTransaction();
+
+    SaveWindowLocation();
+
+    return true;
+  }
+  return false;
+}
+
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdInputImage.xul
@@ -0,0 +1,104 @@
+<?xml version="1.0"?>
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Input Tag Properties Dialog.
+   -
+   - The Initial Developer of the Original Code is
+   - Neil Rashbrook.
+   - Portions created by the Initial Developer are Copyright (C) 2001
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s): Neil Rashbrook <neil@parkwaycc.co.uk>
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either the GNU General Public License Version 2 or later (the "GPL"), or
+   - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the LGPL or the GPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<?xul-overlay href="chrome://editor/content/EdImageOverlay.xul"?> 
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?> 
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorInputProperties.dtd">
+<dialog title="&windowTitleImage.label;"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        onload="Startup();"
+        buttons="accept,cancel"
+        ondialogaccept="return onAccept();"
+        ondialogcancel="return onCancel();">
+
+  <!-- Methods common to all editor dialogs -->
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdInputImage.js"/>
+
+  <broadcaster id="args" value=""/>
+  <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+  <tabbox id="TabBox">
+    <tabs flex="1">
+      <tab id="imageInputTab"/>
+      <tab id="imageLocationTab"/>
+      <tab id="imageDimensionsTab"/>
+      <tab id="imageAppearanceTab"/>
+    </tabs>
+    <tabpanels>
+      <groupbox><caption label="&InputSettings.label;"/>
+        <grid><columns><column/><column/></columns>
+          <rows>
+            <row align="center">
+              <label value="&InputName.label;"/>
+              <textbox id="InputName"/>
+            </row>
+            <row>
+              <spacer/>
+              <checkbox id="InputDisabled" label="&InputDisabled.label;"/>
+            </row>
+            <row align="center">
+              <label value="&tabIndex.label;"/>
+              <hbox>
+                <textbox id="InputTabIndex" class="narrow" oninput="forceInteger(this.id);"/>
+              </hbox>
+            </row>
+          </rows>
+        </grid>
+      </groupbox>
+
+      <!-- panels overlayed from EdImageOverlay.xul -->
+      <vbox id="imageLocation"/>
+      <vbox id="imageDimensions"/>
+      <hbox id="imageAppearance"/>
+
+    </tabpanels>
+  </tabbox>
+
+  <hbox align="end">
+    <groupbox id="imagePreview"/>
+
+    <!-- from EdDialogOverlay -->
+    <vbox id="AdvancedEdit"/>
+  </hbox>
+
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdInputProps.js
@@ -0,0 +1,359 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Input Tag Properties Dialog.
+ *
+ * The Initial Developer of the Original Code is
+ * Neil Rashbrook.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s): Neil Rashbrook <neil@parkwaycc.co.uk>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var insertNew;
+var inputElement;
+
+// dialog initialization code
+
+function Startup()
+{
+  var editor = GetCurrentEditor();
+  if (!editor)
+  {
+    dump("Failed to get active editor!\n");
+    window.close();
+    return;
+  }
+
+  gDialog = {
+    accept:             document.documentElement.getButton("accept"),
+    inputType:          document.getElementById("InputType"),
+    inputNameDeck:      document.getElementById("InputNameDeck"),
+    inputName:          document.getElementById("InputName"),
+    inputValueDeck:     document.getElementById("InputValueDeck"),
+    inputValue:         document.getElementById("InputValue"),
+    inputDeck:          document.getElementById("InputDeck"),
+    inputChecked:       document.getElementById("InputChecked"),
+    inputSelected:      document.getElementById("InputSelected"),
+    inputReadOnly:      document.getElementById("InputReadOnly"),
+    inputDisabled:      document.getElementById("InputDisabled"),
+    inputTabIndex:      document.getElementById("InputTabIndex"),
+    inputAccessKey:     document.getElementById("InputAccessKey"),
+    inputSize:          document.getElementById("InputSize"),
+    inputMaxLength:     document.getElementById("InputMaxLength"),
+    inputAccept:        document.getElementById("InputAccept"),
+    MoreSection:        document.getElementById("MoreSection"),
+    MoreFewerButton:    document.getElementById("MoreFewerButton"),
+    AdvancedEditButton: document.getElementById("AdvancedEditButton"),
+    AdvancedEditDeck:   document.getElementById("AdvancedEditDeck")
+  };
+
+  // Get a single selected input element
+  const kTagName = "input";
+  try {
+    inputElement = editor.getSelectedElement(kTagName);
+  } catch (e) {}
+
+  if (inputElement)
+    // We found an element and don't need to insert one
+    insertNew = false;
+  else
+  {
+    insertNew = true;
+
+    // We don't have an element selected,
+    //  so create one with default attributes
+    try {
+      inputElement = editor.createElementWithDefaults(kTagName);
+    } catch (e) {}
+
+    if (!inputElement)
+    {
+      dump("Failed to get selected element or create a new one!\n");
+      window.close();
+      return;
+    }
+
+    var imgElement = editor.getSelectedElement("img");
+    if (imgElement)
+    {
+      // We found an image element, convert it to an input type="image"
+      inputElement.setAttribute("type", "image");
+
+      var attributes = ["src", "alt", "width", "height", "hspace", "vspace", "border", "align"];
+      for (i in attributes)
+        inputElement.setAttribute(attributes[i], imgElement.getAttribute(attributes[i]));
+    }
+    else
+      inputElement.setAttribute("value", GetSelectionAsText());
+  }
+
+  // Make a copy to use for AdvancedEdit
+  globalElement = inputElement.cloneNode(false);
+
+  InitDialog();
+
+  InitMoreFewer();
+
+  gDialog.inputType.focus();
+
+  SetWindowLocation();
+}
+
+function InitDialog()
+{
+  var type = globalElement.getAttribute("type");
+  var index = 0;
+  switch (type)
+  {
+    case "button":
+      index = 9;
+      break;
+    case "checkbox":
+      index = 2;
+      break;
+    case "file":
+      index = 6;
+      break;
+    case "hidden":
+      index = 7;
+      break;
+    case "image":
+      index = 8;
+      break;
+    case "password":
+      index = 1;
+      break;
+    case "radio":
+      index = 3;
+      break;
+    case "reset":
+      index = 5;
+      break;
+    case "submit":
+      index = 4;
+      break;
+  }
+  gDialog.inputType.selectedIndex = index;
+  gDialog.inputName.value = globalElement.getAttribute("name");
+  gDialog.inputValue.value = globalElement.getAttribute("value");
+  gDialog.inputChecked.setAttribute("checked", globalElement.hasAttribute("checked"));
+  gDialog.inputSelected.setAttribute("checked", globalElement.hasAttribute("checked"));
+  gDialog.inputReadOnly.setAttribute("checked", globalElement.hasAttribute("readonly"));
+  gDialog.inputDisabled.setAttribute("checked", globalElement.hasAttribute("disabled"));
+  gDialog.inputTabIndex.value = globalElement.getAttribute("tabindex");
+  gDialog.inputAccessKey.value = globalElement.getAttribute("accesskey");
+  gDialog.inputSize.value = globalElement.getAttribute("size");
+  gDialog.inputMaxLength.value = globalElement.getAttribute("maxlength");
+  gDialog.inputAccept.value = globalElement.getAttribute("accept");
+  SelectInputType();
+}
+
+function SelectInputType()
+{
+  var index = gDialog.inputType.selectedIndex;
+  gDialog.AdvancedEditDeck.setAttribute("selectedIndex", 0);
+  gDialog.inputNameDeck.setAttribute("selectedIndex", 0);
+  gDialog.inputValueDeck.setAttribute("selectedIndex", 0);
+  gDialog.inputValue.disabled = false;
+  gDialog.inputChecked.disabled = index != 2;
+  gDialog.inputSelected.disabled = index != 3;
+  gDialog.inputReadOnly.disabled = index > 1;
+  gDialog.inputTabIndex.disabled = index == 7;
+  gDialog.inputAccessKey.disabled = index == 7;
+  gDialog.inputSize.disabled = index > 1;
+  gDialog.inputMaxLength.disabled = index > 1;
+  gDialog.inputAccept.disabled = index != 6;
+  switch (index)
+  {
+    case 0:
+    case 1:
+      gDialog.inputValueDeck.setAttribute("selectedIndex", 1);
+      gDialog.inputDeck.setAttribute("selectedIndex", 2);
+      break;
+    case 2:
+      gDialog.inputDeck.setAttribute("selectedIndex", 0);
+      break;
+    case 3:
+      gDialog.inputDeck.setAttribute("selectedIndex", 1);
+      gDialog.inputNameDeck.setAttribute("selectedIndex", 1);
+      break;
+    case 6:
+      gDialog.inputValue.disabled = true;
+      gDialog.inputAccept.disabled = false;
+      break;
+    case 8:
+      gDialog.inputValue.disabled = true;
+      gDialog.AdvancedEditDeck.setAttribute("selectedIndex", 1);
+      gDialog.inputName.removeEventListener("input", onInput, false);
+      break;
+    case 7:
+      gDialog.inputValueDeck.setAttribute("selectedIndex", 1);
+      break;
+  }
+  onInput();
+}
+
+function onInput()
+{
+  var disabled = false;;
+  switch (gDialog.inputType.selectedIndex)
+  {
+  case 3:
+    disabled = disabled || !gDialog.inputValue.value;
+  case 4:
+  case 5:
+    break;
+  case 8:
+    disabled = !globalElement.hasAttribute("src");
+    break;
+  default:
+    disabled = !gDialog.inputName.value
+    break;
+  }
+  if (gDialog.accept.disabled != disabled)
+  {
+    gDialog.accept.disabled = disabled;
+    gDialog.AdvancedEditButton.disabled = disabled;
+  }
+}
+
+function doImageProperties()
+{
+  window.openDialog("chrome://editor/content/EdImageProps.xul",
+                    "_blank", "chrome,close,titlebar,modal", globalElement);
+  window.focus();
+  onInput();
+}
+
+function ValidateData()
+{
+  var attributes = {
+    type: "",
+    name: gDialog.inputName.value,
+    value: gDialog.inputValue.value,
+    tabindex: gDialog.inputTabIndex.value,
+    accesskey: "",
+    size: "",
+    maxlength: "",
+    accept: ""
+  };
+  var index = gDialog.inputType.selectedIndex;
+  var flags = {
+    checked: false,
+    readonly: false,
+    disabled: gDialog.inputDisabled.checked
+  };
+  switch (index)
+  {
+    case 1:
+      attributes.type = "password";
+    case 0:
+      flags.readonly = gDialog.inputReadOnly.checked;
+      attributes.size = gDialog.inputSize.value;
+      attributes.maxlength = gDialog.inputMaxLength.value;
+      break;
+    case 2:
+      attributes.type = "checkbox";
+      flags.checked = gDialog.inputChecked.checked;
+      break;
+    case 3:
+      attributes.type = "radio";
+      flags.checked = gDialog.inputSelected.checked;
+      break;
+    case 4:
+      attributes.type = "submit";
+      attributes.accesskey = gDialog.inputAccessKey.value;
+      break;
+    case 5:
+      attributes.type = "reset";
+      attributes.accesskey = gDialog.inputAccessKey.value;
+      break;
+    case 6:
+      attributes.type = "file";
+      attributes.accept = gDialog.inputAccept.value;
+      attributes.value = "";
+      break;
+    case 7:
+      attributes.type = "hidden";
+      attributes.tabindex = "";
+      break;
+    case 8:
+      attributes.type = "image";
+      attributes.value = "";
+      break;
+    case 9:
+      attributes.type = "button";
+      attributes.accesskey = gDialog.inputAccessKey.value;
+      break;
+  }
+  for (var a in attributes)
+  {
+    if (attributes[a])
+      globalElement.setAttribute(a, attributes[a]);
+    else
+      globalElement.removeAttribute(a);
+  }
+  for (var f in flags)
+  {
+    if (flags[f])
+      globalElement.setAttribute(f, "");
+    else
+      globalElement.removeAttribute(f);
+  }
+  return true;
+}
+
+function onAccept()
+{
+  if (ValidateData())
+  {
+    // All values are valid - copy to actual element in doc or
+    //   element created to insert
+
+    var editor = GetCurrentEditor();
+
+    editor.cloneAttributes(inputElement, globalElement);
+
+    if (insertNew)
+    {
+      try {
+        // 'true' means delete the selection before inserting
+        // in case were are converting an image to an input type="image"
+        editor.insertElementAtSelection(inputElement, true);
+      } catch (e) {
+        dump(e);
+      }
+    }
+
+    SaveWindowLocation();
+
+    return true;
+  }
+  return false;
+}
+
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdInputProps.xul
@@ -0,0 +1,156 @@
+<?xml version="1.0"?>
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Input Tag Properties Dialog.
+   -
+   - The Initial Developer of the Original Code is
+   - Neil Rashbrook.
+   - Portions created by the Initial Developer are Copyright (C) 2001
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s): Neil Rashbrook <neil@parkwaycc.co.uk>
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either the GNU General Public License Version 2 or later (the "GPL"), or
+   - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the LGPL or the GPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?> 
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorInputProperties.dtd">
+<dialog title="&windowTitle.label;"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        onload="Startup();"
+        buttons="accept,cancel"
+        ondialogaccept="return onAccept();"
+        ondialogcancel="return onCancel();">
+
+  <!-- Methods common to all editor dialogs -->
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdInputProps.js"/>
+
+  <broadcaster id="args" value=""/>
+  <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+  <groupbox><caption><label control="InputType" value="&InputType.label;" accesskey="&InputType.accesskey;"/></caption>
+    <menulist id="InputType" oncommand="SelectInputType();">
+      <menupopup>
+        <menuitem label="&text.value;"/>
+        <menuitem label="&password.value;"/>
+        <menuitem label="&checkbox.value;"/>
+        <menuitem label="&radio.value;"/>
+        <menuitem label="&submit.value;"/>
+        <menuitem label="&reset.value;"/>
+        <menuitem label="&file.value;"/>
+        <menuitem label="&hidden.value;"/>
+        <menuitem label="&image.value;"/>
+        <menuitem label="&button.value;"/>
+      </menupopup>
+    </menulist>
+  </groupbox>
+
+  <groupbox><caption label="&InputSettings.label;"/>
+    <grid><columns><column/><column/></columns>
+      <rows>
+        <row align="center">
+          <deck id="InputNameDeck">
+            <label control="InputName" value="&InputName.label;" accesskey="&Name.accesskey;"/>
+            <label control="InputName" value="&GroupName.label;" accesskey="&Name.accesskey;"/>
+          </deck>
+          <textbox id="InputName" oninput="onInput();"/>
+        </row>
+        <row align="center">
+          <deck id="InputValueDeck">
+            <label control="InputValue" value="&InputValue.label;" accesskey="&Value.accesskey;"/>
+            <label control="InputValue" value="&InitialValue.label;" accesskey="&Value.accesskey;"/>
+          </deck>
+          <textbox id="InputValue" oninput="onInput();"/>
+        </row>
+        <row>
+          <spacer/>
+          <deck id="InputDeck" persist="index">
+            <checkbox id="InputChecked" label="&InputChecked.label;" accesskey="&InputChecked.accesskey;"/>
+            <checkbox id="InputSelected" label="&InputSelected.label;" accesskey="&InputSelected.accesskey;"/>
+            <checkbox id="InputReadOnly" label="&InputReadOnly.label;" accesskey="&InputReadOnly.accesskey;"/>
+          </deck>
+        </row>
+      </rows>
+    </grid>
+    <hbox>
+      <button id="MoreFewerButton" oncommand="onMoreFewer();" persist="more"/>
+    </hbox>
+    <grid id="MoreSection" align="start">
+      <columns><column/><column/></columns>
+      <rows>
+        <row>
+          <spacer/>
+          <checkbox id="InputDisabled" label="&InputDisabled.label;" accesskey="&InputDisabled.accesskey;"/>
+        </row>
+        <row align="center">
+          <label control="InputTabIndex" value="&tabIndex.label;" accesskey="&tabIndex.accesskey;"/>
+          <hbox>
+            <textbox id="InputTabIndex" class="narrow" oninput="forceInteger(this.id);"/>
+          </hbox>
+        </row>
+        <row align="center">
+          <label control="InputAccessKey" value="&AccessKey.label;" accesskey="&AccessKey.accesskey;"/>
+          <hbox>
+            <textbox id="InputAccessKey" class="narrow"/>
+          </hbox>
+        </row>
+        <row align="center">
+          <label control="InputSize" value="&TextSize.label;" accesskey="&TextSize.accesskey;"/>
+          <hbox>
+            <textbox id="InputSize" class="narrow" oninput="forceInteger(this.id);"/>
+          </hbox>
+        </row>
+        <row align="center">
+          <label control="InputMaxLength" value="&TextLength.label;" accesskey="&TextLength.accesskey;"/>
+          <hbox>
+            <textbox id="InputMaxLength" class="narrow" oninput="forceInteger(this.id);"/>
+          </hbox>
+        </row>
+        <row align="center">
+          <label control="InputAccept" value="&Accept.label;" accesskey="&Accept.accesskey;"/>
+          <textbox id="InputAccept"/>
+        </row>
+      </rows>
+    </grid>
+  </groupbox>
+
+  <!-- from EdDialogOverlay -->
+  <hbox flex="1" style="margin-top: 0.2em">
+    <!-- This will right-align the button -->
+    <spacer flex="1"/>
+    <deck id="AdvancedEditDeck">
+      <button id="AdvancedEditButton"/>
+      <button label="&ImageProperties.label;" accesskey="&ImageProperties.accesskey;" oncommand="doImageProperties();"/>
+    </deck>
+  </hbox>
+  <separator class="groove"/>
+
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdInsSrc.js
@@ -0,0 +1,89 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Akkana Peck (akkana@netscape.com)
+ *   Charles Manske (cmanske@netscape.com)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* Insert Source HTML dialog */
+
+function Startup()
+{
+  var editor = GetCurrentEditor();
+  if (!editor)
+  {
+    window.close();
+    return;
+  }
+
+  document.documentElement.getButton("accept").removeAttribute("default");
+
+  // Create dialog object to store controls for easy access
+  gDialog.srcInput = document.getElementById("srcInput");
+
+  var selection;
+  try {
+    selection = editor.outputToString("text/html", kOutputFormatted | kOutputSelectionOnly | kOutputWrap);
+  } catch (e) {}
+  if (selection)
+  {
+    selection = (selection.replace(/<body[^>]*>/,"")).replace(/<\/body>/,"");
+    if (selection)
+      gDialog.srcInput.value = selection;
+  }
+  // Set initial focus
+  gDialog.srcInput.focus();
+  // Note: We can't set the caret location in a multiline textbox
+  SetWindowLocation();
+}
+
+function onAccept()
+{
+  if (gDialog.srcInput.value)
+  {
+    try {
+      GetCurrentEditor().insertHTML(gDialog.srcInput.value);
+    } catch (e) {}
+  }
+  else
+  {
+    dump("Null value -- not inserting in HTML Source dialog\n");
+    return false;
+  }
+  SaveWindowLocation();
+
+  return true;
+}
+
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdInsSrc.xul
@@ -0,0 +1,77 @@
+<?xml version="1.0"?>
+
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?> 
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorInsertSource.dtd">
+
+<dialog title="&windowTitle.label;"
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    onload = "Startup()"
+    buttonlabelaccept="&insertButton.label;"
+    buttonaccesskeyaccept="&insertButton.accesskey;"
+    ondialogaccept="return onAccept();"
+    ondialogcancel="return onCancel();">
+
+  <!-- Methods common to all editor dialogs -->
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdInsSrc.js"/>
+
+  <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+  <broadcaster id="args" value=""/>
+
+  <label id="srcMessage" value="&sourceEditField.label;"/>
+  <vbox flex="1" style="width: 30em; height: 20em;">
+    <textbox id="srcInput" multiline="true" rows="1" style="width: 1em" flex="1" class="uri-element"/>
+  </vbox>
+  <!-- Will this accept the embedded HTML tags? -->
+  <hbox>
+    <spacer class="bigspacer"/>
+    <label value="&example.label;"/>
+    <label class="bold" value="&exampleOpenTag.label;"/>
+    <label class="bold italic" value="&exampleText.label;"/>
+    <label class="bold" value="&exampleCloseTag.label;"/>
+  </hbox>
+  <spacer class="spacer"/>
+  <separator class="groove"/>
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdInsertChars.js
@@ -0,0 +1,445 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Baki Bon <bakibon@yahoo.com>   (original author)
+ *   Charles Manske (cmanske@netscape.com)
+ *   Neil Rashbrook (neil@parkwaycc.co.uk)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+//------------------------------------------------------------------
+// From Unicode 3.0 Page 54. 3.11 Conjoining Jamo Behavior
+var SBase = 0xac00;
+var LBase = 0x1100;
+var VBase = 0x1161;
+var TBase = 0x11A7;
+var LCount = 19;
+var VCount = 21;
+var TCount = 28;
+var NCount = VCount * TCount;
+// End of Unicode 3.0
+
+// dialog initialization code
+function Startup()
+{
+  if (!GetCurrentEditor())
+  {
+    window.close();
+    return;
+  }
+
+  StartupLatin();
+
+  // Set a variable on the opener window so we
+  //  can track ownership of close this window with it
+  window.opener.InsertCharWindow = window;
+  window.sizeToContent();
+
+  SetWindowLocation();
+}
+
+function onAccept()
+{
+  // Insert the character
+  try {
+    GetCurrentEditor().insertText(LatinM.label);
+  } catch(e) {}
+
+  // Set persistent attributes to save
+  //  which category, letter, and character modifier was used
+  CategoryGroup.setAttribute("category", category);
+  CategoryGroup.setAttribute("letter_index", indexL);
+  CategoryGroup.setAttribute("char_index", indexM);
+  
+  // Don't close the dialog
+  return false;
+}
+
+// Don't allow inserting in HTML Source Mode
+function onFocus()
+{
+  var enable = true;
+  if ("gEditorDisplayMode" in window.opener)
+    enable = !window.opener.IsInHTMLSourceMode();
+
+  SetElementEnabled(document.documentElement.getButton("accept"), enable);
+}
+
+function onClose()
+{
+  window.opener.InsertCharWindow = null;
+  SaveWindowLocation();
+  return true;
+}
+
+//------------------------------------------------------------------
+var LatinL;
+var LatinM;
+var LatinL_Label;
+var LatinM_Label;
+var indexL=0;
+var indexM=0;
+var indexM_AU=0;
+var indexM_AL=0;
+var indexM_U=0;
+var indexM_L=0;
+var indexM_S=0;
+var LItems=0;
+var category;
+var CategoryGroup;
+var initialize = true;
+
+function StartupLatin()
+{
+
+  LatinL = document.getElementById("LatinL");
+  LatinM = document.getElementById("LatinM");
+  LatinL_Label = document.getElementById("LatinL_Label");
+  LatinM_Label = document.getElementById("LatinM_Label");
+
+  var Symbol      = document.getElementById("Symbol");
+  var AccentUpper = document.getElementById("AccentUpper");
+  var AccentLower = document.getElementById("AccentLower");
+  var Upper       = document.getElementById("Upper");
+  var Lower       = document.getElementById("Lower");
+  CategoryGroup   = document.getElementById("CatGrp");
+
+  // Initialize which radio button is set from persistent attribute...
+  var category = CategoryGroup.getAttribute("category");
+
+  // ...as well as indexes into the letter and character lists
+  var index = Number(CategoryGroup.getAttribute("letter_index"));
+  if (index && index >= 0)
+    indexL = index;
+  index = Number(CategoryGroup.getAttribute("char_index"));
+  if (index && index >= 0)
+    indexM = index;
+
+
+  switch (category)
+  {
+    case "AccentUpper": // Uppercase Diacritical
+      CategoryGroup.selectedItem = AccentUpper;
+      indexM_AU = indexM;
+      break;
+    case "AccentLower": // Lowercase Diacritical
+      CategoryGroup.selectedItem = AccentLower;
+      indexM_AL = indexM;
+      break;
+    case "Upper": // Uppercase w/o Diacritical
+      CategoryGroup.selectedItem = Upper;
+      indexM_U = indexM;
+      break;
+    case "Lower": // Lowercase w/o Diacritical
+      CategoryGroup.selectedItem = Lower;
+      indexM_L = indexM;
+      break;
+    default:
+      category = "Symbol";
+      CategoryGroup.selectedItem = Symbol;
+      indexM_S = indexM;
+      break;
+  }
+
+  ChangeCategory(category);
+  initialize = false;
+}
+
+function ChangeCategory(newCategory)
+{
+  if (category != newCategory || initialize)
+  {
+    category = newCategory;
+    // Note: Must do L before M to set LatinL.selectedIndex
+    UpdateLatinL();
+    UpdateLatinM();
+    UpdateCharacter();
+  }
+}
+
+function SelectLatinLetter()
+{
+  if(LatinL.selectedIndex != indexL )
+  {
+    indexL = LatinL.selectedIndex;
+    UpdateLatinM();
+    UpdateCharacter();
+  }
+}
+
+function SelectLatinModifier()
+{
+  if(LatinM.selectedIndex != indexM )
+  {
+    indexM = LatinM.selectedIndex;
+    UpdateCharacter();
+  }
+}
+function DisableLatinL(disable)
+{
+  if (disable) {
+    LatinL_Label.setAttribute("disabled", "true");
+    LatinL.setAttribute("disabled", "true");
+  } else {
+    LatinL_Label.removeAttribute("disabled");
+    LatinL.removeAttribute("disabled");
+  }
+}
+
+function UpdateLatinL()
+{
+  LatinL.removeAllItems();
+  if (category == "AccentUpper" || category == "AccentLower")
+  {
+    DisableLatinL(false);
+    // No Q or q
+    var alphabet = category == "AccentUpper" ? "ABCDEFGHIJKLMNOPRSTUVWXYZ" : "abcdefghijklmnoprstuvwxyz";
+    for (var letter = 0; letter < alphabet.length; letter++)
+      LatinL.appendItem(alphabet.charAt(letter));
+
+    LatinL.selectedIndex = indexL;
+  }
+  else
+  {
+    // Other categories don't hinge on a "letter"
+    DisableLatinL(true);
+    // Note: don't change the indexL so it can be used next time
+  }
+}
+
+function UpdateLatinM()
+{
+  LatinM.removeAllItems();
+  var i, accent;
+  switch(category)
+  {
+    case "AccentUpper": // Uppercase Diacritical
+      accent = upper[indexL];
+      for(i=0; i < accent.length; i++)
+        LatinM.appendItem(accent.charAt(i));
+
+      if(indexM_AU < accent.length)
+        indexM = indexM_AU;
+      else
+        indexM = accent.length - 1;
+      indexM_AU = indexM;
+      break;
+
+    case "AccentLower": // Lowercase Diacritical
+      accent = lower[indexL];
+      for(i=0; i < accent.length; i++)
+        LatinM.appendItem(accent.charAt(i));
+
+      if(indexM_AL < accent.length)
+        indexM = indexM_AL;
+      else
+        indexM = lower[indexL].length - 1;
+      indexM_AL = indexM;
+      break;
+
+    case "Upper": // Uppercase w/o Diacritical
+      for(i=0; i < otherupper.length; i++)
+        LatinM.appendItem(otherupper.charAt(i));
+
+      if(indexM_U < otherupper.length)
+        indexM = indexM_U;
+      else
+        indexM = otherupper.length - 1;
+      indexM_U = indexM;
+      break;
+
+    case "Lower": // Lowercase w/o Diacritical
+      for(i=0; i < otherlower.length; i++)
+        LatinM.appendItem(otherlower.charAt(i));
+
+      if(indexM_L < otherlower.length)
+        indexM = indexM_L;
+      else
+        indexM = otherlower.length - 1;
+      indexM_L = indexM;
+      break;
+
+    case "Symbol": // Symbol
+      for(i=0; i < symbol.length; i++)
+        LatinM.appendItem(symbol.charAt(i));
+
+      if(indexM_S < symbol.length)
+        indexM = indexM_S;
+      else
+        indexM = symbol.length - 1;
+      indexM_S = indexM;
+      break;
+  }
+  LatinM.selectedIndex = indexM;
+}
+
+function UpdateCharacter()
+{
+  indexM = LatinM.selectedIndex;
+
+  switch(category)
+  {
+    case "AccentUpper": // Uppercase Diacritical
+      indexM_AU = indexM;
+      break;
+    case "AccentLower": // Lowercase Diacritical
+      indexM_AL = indexM;
+      break;
+    case "Upper": // Uppercase w/o Diacritical
+      indexM_U = indexM;
+      break;
+    case "Lower": // Lowercase w/o Diacritical
+      indexM_L = indexM;
+      break;
+    case "Symbol":
+      indexM_S = indexM;
+      break;
+  }
+//dump("Letter Index="+indexL+", Character Index="+indexM+", Character = "+LatinM.label+"\n");
+}
+
+const upper=[
+  // A
+  "\u00c0\u00c1\u00c2\u00c3\u00c4\u00c5\u0100\u0102\u0104\u01cd\u01de\u01de\u01e0\u01fa\u0200\u0202\u0226\u1e00\u1ea0\u1ea2\u1ea4\u1ea6\u1ea8\u1eaa\u1eac\u1eae\u1eb0\u1eb2\u1eb4\u1eb6",
+  // B
+  "\u0181\u0182\u0184\u1e02\u1e04\u1e06",
+  // C
+  "\u00c7\u0106\u0108\u010a\u010c\u0187\u1e08",
+  // D
+  "\u010e\u0110\u0189\u018a\u1e0a\u1e0c\u1e0e\u1e10\u1e12",
+  // E
+  "\u00C8\u00C9\u00CA\u00CB\u0112\u0114\u0116\u0118\u011A\u0204\u0206\u0228\u1e14\u1e16\u1e18\u1e1a\u1e1c\u1eb8\u1eba\u1ebc\u1ebe\u1ec0\u1ec2\u1ec4\u1ec6",
+  // F
+  "\u1e1e",
+  // G
+  "\u011c\u011E\u0120\u0122\u01e4\u01e6\u01f4\u1e20",
+  // H
+  "\u0124\u0126\u021e\u1e22\u1e24\u1e26\u1e28\u1e2a",
+  // I
+  "\u00CC\u00CD\u00CE\u00CF\u0128\u012a\u012C\u012e\u0130\u0208\u020a\u1e2c\u1e2e\u1ec8\u1eca",
+  // J
+  "\u0134\u01f0",
+  // K
+  "\u0136\u0198\u01e8\u1e30\u1e32\u1e34",
+  // L
+  "\u0139\u013B\u013D\u013F\u0141\u1e36\u1e38\u1e3a\u1e3c",
+  // M
+  "\u1e3e\u1e40\u1e42",
+  // N
+  "\u00D1\u0143\u0145\u0147\u014A\u01F8\u1e44\u1e46\u1e48\u1e4a",
+  // O
+  "\u00D2\u00D3\u00D4\u00D5\u00D6\u014C\u014E\u0150\u01ea\u01ec\u020c\u020e\u022A\u022C\u022E\u0230\u1e4c\u1e4e\u1e50\u1e52\u1ecc\u1ece\u1ed0\u1ed2\u1ed4\u1ed6\u1ed8\u1eda\u1edc\u1ede\u1ee0\u1ee2",
+  // P
+  "\u1e54\u1e56",
+  // No Q
+  // R
+  "\u0154\u0156\u0158\u0210\u0212\u1e58\u1e5a\u1e5c\u1e5e",
+  // S
+  "\u015A\u015C\u015E\u0160\u0218\u1e60\u1e62\u1e64\u1e66\u1e68",
+  // T
+  "\u0162\u0164\u0166\u021A\u1e6a\u1e6c\u1e6e\u1e70",
+  // U
+  "\u00D9\u00DA\u00DB\u00DC\u0168\u016A\u016C\u016E\u0170\u0172\u0214\u0216\u1e72\u1e74\u1e76\u1e78\u1e7a\u1ee4\u1ee6\u1ee8\u1eea\u1eec\u1eee\u1ef0",
+  // V
+  "\u1e7c\u1e7e",
+  // W
+  "\u0174\u1e80\u1e82\u1e84\u1e86\u1e88",
+  // X
+  "\u1e8a\u1e8c",
+  // Y
+  "\u00DD\u0176\u0178\u0232\u1e8e\u1ef2\u1ef4\u1ef6\u1ef8",
+  // Z
+  "\u0179\u017B\u017D\u0224\u1e90\u1e92\u1e94"
+];
+
+const lower=[
+  // a
+  "\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5\u0101\u0103\u0105\u01ce\u01df\u01e1\u01fb\u0201\u0203\u0227\u1e01\u1e9a\u1ea1\u1ea3\u1ea5\u1ea7\u1ea9\u1eab\u1ead\u1eaf\u1eb1\u1eb3\u1eb5\u1eb7",
+  // b
+  "\u0180\u0183\u0185\u1e03\u1e05\u1e07",
+  // c
+  "\u00e7\u0107\u0109\u010b\u010d\u0188\u1e09",
+  // d
+  "\u010f\u0111\u1e0b\u1e0d\u1e0f\u1e11\u1e13",
+  // e
+  "\u00e8\u00e9\u00ea\u00eb\u0113\u0115\u0117\u0119\u011b\u0205\u0207\u0229\u1e15\u1e17\u1e19\u1e1b\u1e1d\u1eb9\u1ebb\u1ebd\u1ebf\u1ec1\u1ec3\u1ec5\u1ec7",
+  // f
+  "\u1e1f",
+  // g
+  "\u011d\u011f\u0121\u0123\u01e5\u01e7\u01f5\u1e21",
+  // h
+  "\u0125\u0127\u021f\u1e23\u1e25\u1e27\u1e29\u1e2b\u1e96",
+  // i
+  "\u00ec\u00ed\u00ee\u00ef\u0129\u012b\u012d\u012f\u0131\u01d0\u0209\u020b\u1e2d\u1e2f\u1ec9\u1ecb",
+  // j
+  "\u0135",
+  // k
+  "\u0137\u0138\u01e9\u1e31\u1e33\u1e35",
+  // l
+  "\u013a\u013c\u013e\u0140\u0142\u1e37\u1e39\u1e3b\u1e3d",
+  // m
+  "\u1e3f\u1e41\u1e43",
+  // n
+  "\u00f1\u0144\u0146\u0148\u0149\u014b\u01f9\u1e45\u1e47\u1e49\u1e4b",
+  // o
+  "\u00f2\u00f3\u00f4\u00f5\u00f6\u014d\u014f\u0151\u01d2\u01eb\u01ed\u020d\u020e\u022b\u22d\u022f\u0231\u1e4d\u1e4f\u1e51\u1e53\u1ecd\u1ecf\u1ed1\u1ed3\u1ed5\u1ed7\u1ed9\u1edb\u1edd\u1edf\u1ee1\u1ee3",
+  // p
+  "\u1e55\u1e57",
+  // No q
+  // r
+  "\u0155\u0157\u0159\u0211\u0213\u1e59\u1e5b\u1e5d\u1e5f",
+  // s
+  "\u015b\u015d\u015f\u0161\u0219\u1e61\u1e63\u1e65\u1e67\u1e69",
+  // t
+  "\u0162\u0163\u0165\u0167\u021b\u1e6b\u1e6d\u1e6f\u1e71\u1e97",
+  // u
+  "\u00f9\u00fa\u00fb\u00fc\u0169\u016b\u016d\u016f\u0171\u0173\u01d4\u01d6\u01d8\u01da\u01dc\u0215\u0217\u1e73\u1e75\u1e77\u1e79\u1e7b\u1ee5\u1ee7\u1ee9\u1eeb\u1eed\u1eef\u1ef1",
+  // v
+  "\u1e7d\u1e7f",
+  // w
+  "\u0175\u1e81\u1e83\u1e85\u1e87\u1e89\u1e98",
+  // x
+  "\u1e8b\u1e8d",
+  // y
+  "\u00fd\u00ff\u0177\u0233\u1e8f\u1e99\u1ef3\u1ef5\u1ef7\u1ef9",
+  // z
+  "\u017a\u017c\u017e\u0225\u1e91\u1e93\u1e95"
+];
+
+
+const symbol = "\u00a1\u00a2\u00a3\u00a4\u00a5\u20ac\u00a6\u00a7\u00a8\u00a9\u00aa\u00ab\u00ac\u00ae\u00af\u00b0\u00b1\u00b2\u00b3\u00b4\u00b5\u00b6\u00b7\u00b8\u00b9\u00ba\u00bb\u00bc\u00bd\u00be\u00bf\u00d7\u00f7";
+
+const otherupper = "\u00c6\u00d0\u00d8\u00de\u0132\u0152\u0186\u01c4\u01c5\u01c7\u01c8\u01ca\u01cb\u01F1\u01f2";
+
+const otherlower = "\u00e6\u00f0\u00f8\u00fe\u00df\u0133\u0153\u01c6\u01c9\u01cc\u01f3";
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdInsertChars.xul
@@ -0,0 +1,89 @@
+<?xml version="1.0"?>
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?> 
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorInsertChars.dtd">
+
+<dialog id="insertCharsDlg" title="&windowTitle.label;"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        onload = "Startup()"
+        onfocus = "onFocus()"
+        buttonlabelaccept="&insertButton.label;"
+        buttonlabelcancel="&closeButton.label;"
+        ondialogaccept = "return onAccept();"
+        ondialogcancel = "return onClose();">
+
+  <!-- Methods common to all editor dialogs -->
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdInsertChars.js"/>
+
+  <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+  <broadcaster id="args" value=""/>
+
+  <groupbox><caption label="&category.label;"/>
+    <radiogroup id="CatGrp" persist="category letter_index char_index">
+      <radio id="AccentUpper" label="&accentUpper.label;"   oncommand="ChangeCategory(this.id)"/>
+      <radio id="AccentLower" label="&accentLower.label;"   oncommand="ChangeCategory(this.id)"/>
+      <radio id="Upper"       label="&otherUpper.label;"    oncommand="ChangeCategory(this.id)"/>
+      <radio id="Lower"       label="&otherLower.label;"    oncommand="ChangeCategory(this.id)"/>
+      <radio id="Symbol"      label="&commonSymbols.label;" oncommand="ChangeCategory(this.id)"/>
+    </radiogroup> 
+    <spacer class="spacer"/>
+  </groupbox>
+  <hbox equalsize="always">
+    <vbox flex="1">
+      <!-- value is set in JS from editor.properties strings -->
+      <label id="LatinL_Label" control="LatinL" value="&letter.label;" accesskey="&letter.accessKey;"/>
+      <menulist class="larger" flex="1" id="LatinL" oncommand="SelectLatinLetter()">
+        <menupopup/>
+      </menulist>
+    </vbox>
+    <vbox flex="1">
+      <label id="LatinM_Label" control="LatinM" value="&character.label;" accesskey="&character.accessKey;"/>
+      <menulist class="larger" flex="1" id="LatinM" oncommand="SelectLatinModifier()">
+        <menupopup/>
+      </menulist>
+    </vbox>
+  </hbox>
+  <separator class="groove"/>
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdInsertTOC.js
@@ -0,0 +1,411 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is TOCMaker.
+ *
+ * The Initial Developer of the Original Code is
+ * Daniel Glazman.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Daniel Glazman <daniel@glazman.org> (Original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// tocHeadersArray is the array containing the pairs tag/class
+// defining TOC entries
+var tocHeadersArray = new Array(6);
+
+// a global used when building the TOC
+var currentHeaderLevel = 0;
+
+// a global set to true if the TOC is to be readonly
+var readonly = false;
+
+// a global set to true if user wants indexes in the TOC
+var orderedList = true;
+
+// constants
+const kMozToc                  = "mozToc";
+const kMozTocLength            = 6;
+const kMozTocIdPrefix          = "mozTocId";
+const kMozTocIdPrefixLength    = 8;
+const kMozTocClassPrefix       = "mozToc";
+const kMozTocClassPrefixLength = 6;
+
+// Startup() is called when EdInsertTOC.xul is opened
+function Startup()
+{
+  // early way out if if we have no editor
+  if (!GetCurrentEditor()) {
+    window.close();
+    return;
+  }
+
+  var i, j;
+  // clean the table of tag/class pairs we look for
+  for (i = 0; i < 6; ++i)
+    tocHeadersArray[i] = [ "", "" ];
+
+  // reset all settings
+  for (i = 1; i < 7; ++i) {
+    var menulist = document.getElementById("header" + i + "Menulist");
+    var menuitem = document.getElementById("header" + i + "none");
+    var textbox  = document.getElementById("header" + i + "Class");
+    menulist.selectedItem = menuitem;
+    textbox.setAttribute("disabled", "true");
+  }
+
+  var theDocument = GetCurrentEditor().document;
+
+  // do we already have a TOC in the document ? It should have "mozToc" ID
+  var toc = theDocument.getElementById(kMozToc);
+
+  // default TOC definition, use h1-h6 for TOC entry levels 1-6
+  var headers = "h1 1 h2 2 h3 3 h4 4 h5 5 h6 6";
+
+  var orderedListCheckbox = document.getElementById("orderedListCheckbox");
+  orderedListCheckbox.checked = true;
+
+  if (toc) {
+    // man, there is already a TOC here
+
+    if (toc.getAttribute("class") == "readonly") {
+      // and it's readonly
+      var checkbox = document.getElementById("readOnlyCheckbox");
+      checkbox.checked = true;
+      readonly = true;
+    }
+
+    // let's see if it's an OL or an UL
+    orderedList = (toc.nodeName.toLowerCase() == "ol");
+    orderedListCheckbox.checked = orderedList;
+
+    var nodeList = toc.childNodes;
+    // let's look at the children of the TOC ; if we find a comment beginning
+    // with "mozToc", it contains the TOC definition
+    for (i = 0; i< nodeList.length; ++i) {
+      if (nodeList.item(i).nodeType == Node.COMMENT_NODE &&
+          nodeList.item(i).data.substr(0, kMozTocLength) == kMozToc) {
+        // yep, there is already a definition here; parse it !
+        headers = nodeList.item(i).data.substr(kMozTocLength + 1,
+                                    nodeList.item(i).length - kMozTocLength - 1);
+        break;
+      }
+    }
+  }
+
+  // let's get an array filled with the (tag.class, index level) pairs
+  var headersArray = headers.split(" ");
+
+  for (i = 0; i < headersArray.length; i += 2) {
+    var tag = headersArray[i], className = "";
+    var index = headersArray[i + 1];
+    menulist = document.getElementById("header" + index + "Menulist");
+    if (menulist) {
+      var sep = tag.indexOf(".");
+      if (sep != -1) {
+        // the tag variable contains in fact "tag.className", let's parse
+        // the class and get the real tag name
+        var tmp   = tag.substr(0, sep);
+        className = tag.substr(sep + 1, tag.length - sep - 1);
+        tag = tmp;
+      }
+
+      // update the dialog
+      menuitem = document.getElementById("header" + index +
+                                         tag.toUpperCase());
+      textbox  = document.getElementById("header" + index + "Class");
+      menulist.selectedItem = menuitem;
+      if (tag != "") {
+        textbox.removeAttribute("disabled");
+      }
+      if (className != "") {
+        textbox.value = className;
+      }
+      tocHeadersArray[index - 1] = [ tag, className ];
+    }
+  }
+}
+
+
+function BuildTOC(update)
+{
+  // controlClass() is a node filter that accepts a node if
+  // (a) we don't look for a class (b) we look for a class and
+  // node has it
+  function controlClass(node, index)
+  {
+    currentHeaderLevel = index + 1;
+    if (tocHeadersArray[index][1] == "") {
+      // we are not looking for a specific class, this node is ok
+      return NodeFilter.FILTER_ACCEPT;
+    }
+    if (node.getAttribute("class")) {
+      // yep, we look for a class, let's look at all the classes
+      // the node has
+      var classArray = node.getAttribute("class").split(" ");
+      for (var j = 0; j < classArray.length; j++) {
+        if (classArray[j] == tocHeadersArray[index][1]) {
+          // hehe, we found it...
+          return NodeFilter.FILTER_ACCEPT;
+        }
+      }
+    }
+    return NodeFilter.FILTER_SKIP;
+  }
+
+  // the main node filter for our node iterator
+  // it selects the tag names as specified in the dialog
+  // then calls the controlClass filter above
+  function acceptNode(node)
+  {
+    switch (node.nodeName.toLowerCase())
+    {
+      case tocHeadersArray[0][0]:
+        return controlClass(node, 0);
+        break;
+      case tocHeadersArray[1][0]:
+        return controlClass(node, 1);
+        break;
+      case tocHeadersArray[2][0]:
+        return controlClass(node, 2);
+        break;
+      case tocHeadersArray[3][0]:
+        return controlClass(node, 3);
+        break;
+      case tocHeadersArray[4][0]:
+        return controlClass(node, 4);
+        break;
+      case tocHeadersArray[5][0]:
+        return controlClass(node, 5);
+        break;
+      default:
+        return NodeFilter.FILTER_SKIP;
+        break;
+    }
+    return NodeFilter.FILTER_SKIP;   // placate the js compiler
+  }
+
+  var editor = GetCurrentEditor();
+  var theDocument = editor.document;
+  // let's create a TreeWalker to look for our nodes
+  var treeWalker = theDocument.createTreeWalker(theDocument.documentElement,
+                                                NodeFilter.SHOW_ELEMENT,
+                                                acceptNode,
+                                                true);
+  // we need an array to store all TOC entries we find in the document
+  var tocArray = new Array();
+  if (treeWalker) {
+    var tocSourceNode = treeWalker.nextNode();
+    while (tocSourceNode) {
+      var headerIndex = currentHeaderLevel;
+
+      // we have a node, we need to get all its textual contents
+      var textTreeWalker = theDocument.createTreeWalker(tocSourceNode,
+                                                        NodeFilter.SHOW_TEXT,
+                                                        null,
+                                                        true);
+      var textNode = textTreeWalker.nextNode(), headerText = "";
+      while (textNode) {
+        headerText += textNode.data;
+        textNode = textTreeWalker.nextNode();
+      }
+
+      var anchor = tocSourceNode.firstChild, id;
+      // do we have a named anchor as 1st child of our node ?
+      if (anchor.nodeName.toLowerCase() == "a" &&
+          anchor.hasAttribute("name") &&
+          anchor.getAttribute("name").substr(0, kMozTocIdPrefixLength) == kMozTocIdPrefix) {
+        // yep, get its name
+        id = anchor.getAttribute("name");
+      }
+      else {
+        // no we don't and we need to create one
+        anchor = theDocument.createElement("a");
+        tocSourceNode.insertBefore(anchor, tocSourceNode.firstChild);
+        // let's give it a random ID
+        var c = 1000000 * Math.random();
+        id = kMozTocIdPrefix + Math.round(c);
+        anchor.setAttribute("name",  id);
+        anchor.setAttribute("class", kMozTocClassPrefix +
+                                     tocSourceNode.nodeName.toUpperCase());
+      }
+      // and store that new entry in our array
+      tocArray.push(headerIndex, headerText, id);
+      tocSourceNode = treeWalker.nextNode();
+    }
+  }
+
+  /* generate the TOC itself */
+  headerIndex = 0;
+  var item, toc;
+  for (var i = 0; i < tocArray.length; i += 3) {
+    if (!headerIndex) {
+      // do we need to create an ol/ul container for the first entry ?
+      ++headerIndex;
+      toc = theDocument.getElementById(kMozToc);
+      if (!toc || !update) {
+        // we need to create a list container for the table of contents
+        toc = GetCurrentEditor().createElementWithDefaults(orderedList ? "ol" : "ul");
+        // grrr, we need to create a LI inside the list otherwise
+        // Composer will refuse an empty list and will remove it !
+        var pit = theDocument.createElement("li");
+        toc.appendChild(pit);
+        GetCurrentEditor().insertElementAtSelection(toc, true);
+        // ah, now it's inserted so let's remove the useless list item...
+        toc.removeChild(pit);
+        // we need to recognize later that this list is our TOC
+        toc.setAttribute("id", kMozToc);
+      }
+      else {
+        // we have to update an existing TOC, is the existing TOC of the
+        // desired type (ordered or not) ?
+        if (orderedList != (toc.nodeName.toLowerCase() == "ol")) {
+          // nope, we have to recreate the list
+          var newToc = GetCurrentEditor().createElementWithDefaults(orderedList ? "ol" : "ul");
+          toc.parentNode.insertBefore(newToc, toc);
+          // and remove the old one
+          toc.parentNode.removeChild(toc);
+          toc = newToc;
+          toc.setAttribute("id", kMozToc);
+        }
+        else {
+          // we can keep the list itself but let's get rid of the TOC entries
+          while (toc.hasChildNodes()) 
+            toc.removeChild(toc.lastChild);
+        }
+      }
+      var commentText = "mozToc ";
+      for (var j = 0; j < 6; j++) {
+        if (tocHeadersArray[j][0] != "") {
+          commentText += tocHeadersArray[j][0];
+          if (tocHeadersArray[j][1] != "") {
+            commentText += "." + tocHeadersArray[j][1];
+          }
+          commentText += " " + (j + 1) + " ";
+        }
+      }
+      // important, we have to remove trailing spaces
+      commentText = TrimStringRight(commentText);
+
+      // forge a comment we'll insert in the TOC ; that comment will hold
+      // the TOC definition for us
+      var ct = theDocument.createComment(commentText);
+      toc.appendChild(ct);
+
+      // assign a special class to the TOC top element if the TOC is readonly
+      // the definition of this class is in EditorOverride.css
+      if (readonly) {
+        toc.setAttribute("class", "readonly");
+      }
+      else {
+        toc.removeAttribute("class");
+      }
+
+      // We need a new variable to hold the local ul/ol container
+      // The toplevel TOC element is not the parent element of a
+      // TOC entry if its depth is > 1...
+      var tocList = toc;
+      // create a list item
+      var tocItem = theDocument.createElement("li");
+      // and an anchor in this list item
+      var tocAnchor = theDocument.createElement("a");
+      // make it target the source of the TOC entry
+      tocAnchor.setAttribute("href", "#" + tocArray[i + 2]);
+      // and put the textual contents of the TOC entry in that anchor
+      var tocEntry = theDocument.createTextNode(tocArray[i + 1]);
+      // now, insert everything where it has to be inserted
+      tocAnchor.appendChild(tocEntry);
+      tocItem.appendChild(tocAnchor);
+      tocList.appendChild(tocItem);
+      item = tocList;
+    }
+    else {
+      if (tocArray[i] < headerIndex) {
+        // if the depth of the new TOC entry is less than the depth of the
+        // last entry we created, find the good ul/ol ancestor
+        for (j = headerIndex - tocArray[i]; j > 0; --j) {
+          if (item != toc) {
+            item = item.parentNode.parentNode;
+          }
+        }
+        tocItem = theDocument.createElement("li");
+      }
+      else if (tocArray[i] > headerIndex) {
+        // to the contrary, it's deeper than the last one
+        // we need to create sub ul/ol's and li's
+        for (j = tocArray[i] - headerIndex; j > 0; --j) {
+          tocList = theDocument.createElement(orderedList ? "ol" : "ul");
+          item.lastChild.appendChild(tocList);
+          tocItem = theDocument.createElement("li");
+          tocList.appendChild(tocItem);
+          item = tocList;
+        }
+      }
+      else {
+        tocItem = theDocument.createElement("li");
+      }
+      tocAnchor = theDocument.createElement("a");
+      tocAnchor.setAttribute("href", "#" + tocArray[i + 2]);
+      tocEntry = theDocument.createTextNode(tocArray[i + 1]);
+      tocAnchor.appendChild(tocEntry);
+      tocItem.appendChild(tocAnchor);
+      item.appendChild(tocItem);
+      headerIndex = tocArray[i];
+    }
+  }
+  SaveWindowLocation();
+  return true;
+}
+
+function selectHeader(elt, index)
+{
+  var tag = elt.value;
+  tocHeadersArray[index - 1][0] = tag;
+  var textbox = document.getElementById("header" + index + "Class");
+  if (tag == "") {
+    textbox.setAttribute("disabled", "true");
+  }
+  else {
+    textbox.removeAttribute("disabled");
+  }
+}
+
+function changeClass(elt, index)
+{
+  tocHeadersArray[index - 1][1] = elt.value;
+}
+
+function ToggleReadOnlyToc(elt)
+{
+  readonly = elt.checked;
+}
+
+function ToggleOrderedList(elt)
+{
+  orderedList = elt.checked;
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdInsertTOC.xul
@@ -0,0 +1,263 @@
+<?xml version="1.0"?>
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is TocMaker.
+   -
+   - The Initial Developer of the Original Code is
+   - Daniel Glazman.
+   - Portions created by the Initial Developer are Copyright (C) 2002
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -   Original author: Daniel Glazman (daniel@glazman.org)
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either the GNU General Public License Version 2 or later (the "GPL"), or
+   - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the LGPL or the GPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<?xul-overlay href="chrome://global/content/dialogOverlay.xul"?>
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?>
+<?xul-overlay href="chrome://global/content/globalOverlay.xul"?>
+
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorInsertTOC.dtd">
+
+<dialog title="&Window.title;"
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    xmlns:html="http://www.w3.org/1999/xhtml"
+    onload="Startup();"
+    ondialogaccept="return BuildTOC(true);"
+    oncancel="window.close(); return true;">
+
+  <!-- Methods common to all editor dialogs -->
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdInsertTOC.js"/>
+  <script type="application/x-javascript" src="chrome://global/content/dialogOverlay.js" />
+
+  <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+  <spacer id="dummy" style="display:none"/>
+  <broadcaster id="args" value=""/>
+  <vbox flex="1">
+    <groupbox><caption label="&buildToc.label;"/>
+      <grid>
+        <columns><column/><column style="min-width: 6em"/><column/></columns>
+        <rows>
+          <row align="center">
+            <spacer/>
+            <label value="&tag.label;"/>
+            <label value="&class.label;"/>
+          </row>
+          <row align="center">
+            <label value="&header1.label;"/>
+            <menulist id="header1Menulist">
+              <menupopup>
+                <menuitem id="header1none" label="--" value=""
+                          oncommand="selectHeader(this, 1)"/>
+                <menuseparator/>
+                <menuitem id="header1H1"  label="h1"  value="h1"
+                          oncommand="selectHeader(this, 1)"/>
+                <menuitem id="header1H2"  label="h2"  value="h2"
+                          oncommand="selectHeader(this, 1)"/>
+                <menuitem id="header1H3"  label="h3"  value="h3"
+                          oncommand="selectHeader(this, 1)"/>
+                <menuitem id="header1H4"  label="h4"  value="h4"
+                          oncommand="selectHeader(this, 1)"/>
+                <menuitem id="header1H5"  label="h5"  value="h5"
+                          oncommand="selectHeader(this, 1)"/>
+                <menuitem id="header1H6"  label="h6"  value="h6"
+                          oncommand="selectHeader(this, 1)"/>
+                <menuitem id="header1DIV" label="div" value="div"
+                          oncommand="selectHeader(this, 1)"/>
+                <menuitem id="header1P"   label="p"   value="p"
+                          oncommand="selectHeader(this, 1)"/>
+              </menupopup>
+            </menulist>
+            <textbox id="header1Class" size="10"
+                     oninput="changeClass(this, 1)"/>
+          </row>
+
+          <row align="center">
+            <label value="&header2.label;"/>
+            <menulist id="header2Menulist">
+              <menupopup>
+                <menuitem id="header2none" label="--" value=""
+                          oncommand="selectHeader(this, 2)"/>
+                <menuseparator/>
+                <menuitem id="header2H1"  label="h1"  value="h1"
+                          oncommand="selectHeader(this, 2)"/>
+                <menuitem id="header2H2"  label="h2"  value="h2"
+                          oncommand="selectHeader(this, 2)"/>
+                <menuitem id="header2H3"  label="h3"  value="h3"
+                          oncommand="selectHeader(this, 2)"/>
+                <menuitem id="header2H4"  label="h4"  value="h4"
+                          oncommand="selectHeader(this, 2)"/>
+                <menuitem id="header2H5"  label="h5"  value="h5"
+                          oncommand="selectHeader(this, 2)"/>
+                <menuitem id="header2H6"  label="h6"  value="h6"
+                          oncommand="selectHeader(this, 2)"/>
+                <menuitem id="header2DIV" label="div" value="div"
+                          oncommand="selectHeader(this, 2)"/>
+                <menuitem id="header2P"   label="p"   value="p"
+                          oncommand="selectHeader(this, 2)"/>
+              </menupopup>
+            </menulist>
+            <textbox id="header2Class" size="10"
+                     oninput="changeClass(this, 2)"/>
+          </row>
+
+          <row align="center">
+            <label value="&header3.label;"/>
+            <menulist id="header3Menulist">
+              <menupopup>
+                <menuitem id="header3none" label="--" value=""
+                          oncommand="selectHeader(this, 3)"/>
+                <menuseparator/>
+                <menuitem id="header3H1"  label="h1"  value="h1"
+                          oncommand="selectHeader(this, 3)"/>
+                <menuitem id="header3H2"  label="h2"  value="h2"
+                          oncommand="selectHeader(this, 3)"/>
+                <menuitem id="header3H3"  label="h3"  value="h3"
+                          oncommand="selectHeader(this, 3)"/>
+                <menuitem id="header3H4"  label="h4"  value="h4"
+                          oncommand="selectHeader(this, 3)"/>
+                <menuitem id="header3H5"  label="h5"  value="h5"
+                          oncommand="selectHeader(this, 3)"/>
+                <menuitem id="header3H6"  label="h6"  value="h6"
+                          oncommand="selectHeader(this, 3)"/>
+                <menuitem id="header3DIV" label="div" value="div"
+                          oncommand="selectHeader(this, 3)"/>
+                <menuitem id="header3P"   label="p"   value="p"
+                          oncommand="selectHeader(this, 3)"/>
+              </menupopup>
+            </menulist>
+            <textbox id="header3Class" size="10"
+                     oninput="changeClass(this, 3)"/>
+          </row>
+
+          <row align="center">
+            <label value="&header4.label;"/>
+            <menulist id="header4Menulist">
+              <menupopup>
+                <menuitem id="header4none" label="--" value=""
+                          oncommand="selectHeader(this, 4)"/>
+                <menuseparator/>
+                <menuitem id="header4H1"  label="h1"  value="h1"
+                          oncommand="selectHeader(this, 4)"/>
+                <menuitem id="header4H2"  label="h2"  value="h2"
+                          oncommand="selectHeader(this, 4)"/>
+                <menuitem id="header4H3"  label="h3"  value="h3"
+                          oncommand="selectHeader(this, 4)"/>
+                <menuitem id="header4H4"  label="h4"  value="h4"
+                          oncommand="selectHeader(this, 4)"/>
+                <menuitem id="header4H5"  label="h5"  value="h5"
+                          oncommand="selectHeader(this, 4)"/>
+                <menuitem id="header4H6"  label="h6"  value="h6"
+                          oncommand="selectHeader(this, 4)"/>
+                <menuitem id="header4DIV" label="div" value="div"
+                          oncommand="selectHeader(this, 4)"/>
+                <menuitem id="header4P"   label="p"   value="p"
+                          oncommand="selectHeader(this, 4)"/>
+              </menupopup>
+            </menulist>
+            <textbox id="header4Class" size="10"
+                     oninput="changeClass(this, 4)"/>
+          </row>
+
+          <row align="center">
+            <label value="&header5.label;"/>
+            <menulist id="header5Menulist">
+              <menupopup>
+                <menuitem id="header5none" label="--" value=""
+                          oncommand="selectHeader(this, 5)"/>
+                <menuseparator/>
+                <menuitem id="header5H1"  label="h1"  value="h1"
+                          oncommand="selectHeader(this, 5)"/>
+                <menuitem id="header5H2"  label="h2"  value="h2"
+                          oncommand="selectHeader(this, 5)"/>
+                <menuitem id="header5H3"  label="h3"  value="h3"
+                          oncommand="selectHeader(this, 5)"/>
+                <menuitem id="header5H4"  label="h4"  value="h4"
+                          oncommand="selectHeader(this, 5)"/>
+                <menuitem id="header5H5"  label="h5"  value="h5"
+                          oncommand="selectHeader(this, 5)"/>
+                <menuitem id="header5H6"  label="h6"  value="h6"
+                          oncommand="selectHeader(this, 5)"/>
+                <menuitem id="header5DIV" label="div" value="div"
+                          oncommand="selectHeader(this, 5)"/>
+                <menuitem id="header5P"   label="p"   value="p"
+                          oncommand="selectHeader(this, 5)"/>
+              </menupopup>
+            </menulist>
+            <textbox id="header5Class" size="10"
+                     oninput="changeClass(this, 5)"/>
+          </row>
+
+          <row align="center">
+            <label value="&header6.label;"/>
+            <menulist id="header6Menulist">
+              <menupopup>
+                <menuitem id="header6none" label="--" value=""
+                          oncommand="selectHeader(this, 6)"/>
+                <menuseparator/>
+                <menuitem id="header6H1"  label="h1"  value="h1"
+                          oncommand="selectHeader(this, 6)"/>
+                <menuitem id="header6H2"  label="h2"  value="h2"
+                          oncommand="selectHeader(this, 6)"/>
+                <menuitem id="header6H3"  label="h3"  value="h3"
+                          oncommand="selectHeader(this, 6)"/>
+                <menuitem id="header6H4"  label="h4"  value="h4"
+                          oncommand="selectHeader(this, 6)"/>
+                <menuitem id="header6H5"  label="h5"  value="h5"
+                          oncommand="selectHeader(this, 6)"/>
+                <menuitem id="header6H6"  label="h6"  value="h6"
+                          oncommand="selectHeader(this, 6)"/>
+                <menuitem id="header6DIV" label="div" value="div"
+                          oncommand="selectHeader(this, 6)"/>
+                <menuitem id="header6P"   label="p"   value="p"
+                          oncommand="selectHeader(this, 6)"/>
+              </menupopup>
+            </menulist>
+            <textbox id="header6Class" size="10"
+                     oninput="changeClass(this, 6)"/>
+          </row>
+        </rows>
+      </grid>
+    </groupbox>
+    <vbox>
+      <checkbox id="orderedListCheckbox"
+                label="&orderedList.label;"
+                oncommand="ToggleOrderedList(this)"/>
+      <checkbox id="readOnlyCheckbox"
+                label="&makeReadOnly.label;"
+                oncommand="ToggleReadOnlyToc(this)"/>
+    </vbox>
+    <separator class="groove"/>
+  </vbox>
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdInsertTable.js
@@ -0,0 +1,252 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+//Cancel() is in EdDialogCommon.js
+var gTableElement = null;
+var gRows;
+var gColumns;
+var gActiveEditor;
+
+// dialog initialization code
+function Startup()
+{
+  gActiveEditor = GetCurrentTableEditor();
+  if (!gActiveEditor)
+  {
+    dump("Failed to get active editor!\n");
+    window.close();
+    return;
+  }
+
+  try {
+    gTableElement = gActiveEditor.createElementWithDefaults("table");
+  } catch (e) {}
+
+  if(!gTableElement)
+  {
+    dump("Failed to create a new table!\n");
+    window.close();
+    return;
+  }
+  gDialog.rowsInput    = document.getElementById("rowsInput");
+  gDialog.columnsInput = document.getElementById("columnsInput");
+  gDialog.widthInput = document.getElementById("widthInput");
+  gDialog.borderInput = document.getElementById("borderInput");
+  gDialog.widthPixelOrPercentMenulist = document.getElementById("widthPixelOrPercentMenulist");
+  gDialog.OkButton = document.documentElement.getButton("accept");
+
+  // Make a copy to use for AdvancedEdit
+  globalElement = gTableElement.cloneNode(false);
+  try {
+    if (GetPrefs().getBoolPref("editor.use_css") && IsHTMLEditor()
+        && !(gActiveEditor.flags & Components.interfaces.nsIPlaintextEditor.eEditorMailMask))
+    {
+      // only for Composer and not for htmlmail
+      globalElement.setAttribute("style", "text-align: left;");
+    }
+  } catch (e) {}
+
+  // Initialize all widgets with image attributes
+  InitDialog();
+
+  // Set initial number to 2 rows, 2 columns:
+  // Note, these are not attributes on the table,
+  //  so don't put them in InitDialog(),
+  //  else the user's values will be trashed when they use 
+  //  the Advanced Edit dialog
+  gDialog.rowsInput.value = 2;
+  gDialog.columnsInput.value = 2;
+
+  // If no default value on the width, set to 100%
+  if (gDialog.widthInput.value.length == 0)
+  {
+    gDialog.widthInput.value = "100";
+    gDialog.widthPixelOrPercentMenulist.selectedIndex = 1;
+  }
+
+  SetTextboxFocusById("rowsInput");
+
+  SetWindowLocation();
+}
+
+// Set dialog widgets with attribute data
+// We get them from globalElement copy so this can be used
+//   by AdvancedEdit(), which is shared by all property dialogs
+function InitDialog()
+{  
+  // Get default attributes set on the created table:
+  // Get the width attribute of the element, stripping out "%"
+  // This sets contents of menu combobox list
+  // 2nd param = null: Use current selection to find if parent is table cell or window
+  gDialog.widthInput.value = InitPixelOrPercentMenulist(globalElement, null, "width", "widthPixelOrPercentMenulist", gPercent);
+  gDialog.borderInput.value = globalElement.getAttribute("border");
+}
+
+function ChangeRowOrColumn(id)
+{
+  // Allow only integers
+  forceInteger(id);
+
+  // Enable OK only if both rows and columns have a value > 0
+  var enable = gDialog.rowsInput.value.length > 0 && 
+                              gDialog.rowsInput.value > 0 &&
+                              gDialog.columnsInput.value.length > 0 &&
+                              gDialog.columnsInput.value > 0;
+
+  SetElementEnabled(gDialog.OkButton, enable);
+  SetElementEnabledById("AdvancedEditButton1", enable);
+}
+
+
+// Get and validate data from widgets.
+// Set attributes on globalElement so they can be accessed by AdvancedEdit()
+function ValidateData()
+{
+  gRows = ValidateNumber(gDialog.rowsInput, null, 1, gMaxRows, null, null, true)
+  if (gValidationError)
+    return false;
+
+  gColumns = ValidateNumber(gDialog.columnsInput, null, 1, gMaxColumns, null, null, true)
+  if (gValidationError)
+    return false;
+
+  // Set attributes: NOTE: These may be empty strings (last param = false)
+  ValidateNumber(gDialog.borderInput, null, 0, gMaxPixels, globalElement, "border", false);
+  // TODO: Deal with "BORDER" without value issue
+  if (gValidationError) return false;
+
+  ValidateNumber(gDialog.widthInput, gDialog.widthPixelOrPercentMenulist,
+                 1, gMaxTableSize, globalElement, "width", false);
+  if (gValidationError)
+    return false;
+
+  return true;
+}
+
+
+function onAccept()
+{
+  if (ValidateData())
+  {
+    gActiveEditor.beginTransaction();
+    try {
+      gActiveEditor.cloneAttributes(gTableElement, globalElement);
+
+      // Create necessary rows and cells for the table
+      var tableBody = gActiveEditor.createElementWithDefaults("tbody");
+      if (tableBody)
+      {
+        gTableElement.appendChild(tableBody);
+
+        // Create necessary rows and cells for the table
+        for (var i = 0; i < gRows; i++)
+        {
+          var newRow = gActiveEditor.createElementWithDefaults("tr");
+          if (newRow)
+          {
+            tableBody.appendChild(newRow);
+            for (var j = 0; j < gColumns; j++)
+            {
+              var newCell = gActiveEditor.createElementWithDefaults("td");
+              if (newCell)
+              {
+                newRow.appendChild(newCell);
+              }
+            }
+          }
+        }
+      }
+      // Detect when entire cells are selected:
+        // Get number of cells selected
+      var tagNameObj = { value: "" };
+      var countObj = { value: 0 };
+      var element = gActiveEditor.getSelectedOrParentTableElement(tagNameObj, countObj);
+      var deletePlaceholder = false;
+
+      if (tagNameObj.value == "table")
+      {
+        //Replace entire selected table with new table, so delete the table
+        gActiveEditor.deleteTable();
+      }
+      else if (tagNameObj.value == "td")
+      {
+        if (countObj.value >= 1)
+        {
+          if (countObj.value > 1)
+          {
+            // Assume user wants to replace a block of
+            //  contiguous cells with a table, so
+            //  join the selected cells
+            gActiveEditor.joinTableCells(false);
+          
+            // Get the cell everything was merged into
+            element = gActiveEditor.getFirstSelectedCell();
+          
+            // Collapse selection into just that cell
+            gActiveEditor.selection.collapse(element,0);
+          }
+
+          if (element)
+          {
+            // Empty just the contents of the cell
+            gActiveEditor.deleteTableCellContents();
+          
+            // Collapse selection to start of empty cell...
+            gActiveEditor.selection.collapse(element,0);
+            // ...but it will contain a <br> placeholder
+            deletePlaceholder = true;
+          }
+        }
+      }
+
+      // true means delete selection when inserting
+      gActiveEditor.insertElementAtSelection(gTableElement, true);
+
+      if (deletePlaceholder && gTableElement && gTableElement.nextSibling)
+      {
+        // Delete the placeholder <br>
+        gActiveEditor.deleteNode(gTableElement.nextSibling);
+      }
+    } catch (e) {}
+
+    gActiveEditor.endTransaction();
+
+    SaveWindowLocation();
+    return true;
+  }
+  return false;
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdInsertTable.xul
@@ -0,0 +1,105 @@
+<?xml version="1.0"?>
+
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-2000
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?> 
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorInsertTable.dtd">
+
+<dialog title="&windowTitle.label;"
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    onload = "Startup()"
+    ondialogaccept="return onAccept();"
+    ondialogcancel="return onCancel();">
+
+  <!-- Methods common to all editor dialogs -->
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdInsertTable.js"/>
+
+  <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+  <broadcaster id="args" value=""/>
+  <groupbox><caption label="&size.label;"/>
+    <grid>
+      <columns>
+        <column flex="1"/>
+        <column flex="1"/>
+        <column flex="6"/>
+      </columns>
+      <rows>
+        <row align="center">
+          <label control="rowsInput" class="align-right"
+                 value="&numRowsEditField.label;"
+                 accesskey="&numRowsEditField.accessKey;"/>
+          <textbox class="narrow" id="rowsInput" oninput="ChangeRowOrColumn(this.id)" />
+          <spacer/>
+        </row>
+        <row align="center">
+          <label control="columnsInput" class="align-right"
+                 value="&numColumnsEditField.label;"
+                 accesskey="&numColumnsEditField.accessKey;"/>
+          <textbox class="narrow" id="columnsInput" oninput="ChangeRowOrColumn(this.id)" />
+          <spacer/>
+        </row>
+        <row align="center">
+          <label control="widthInput" class="align-right"
+                 value="&widthEditField.label;"
+                 accesskey="&widthEditField.accessKey;"/>
+          <textbox class="narrow" id="widthInput" oninput="forceInteger(this.id)" />
+          <menulist id="widthPixelOrPercentMenulist" flex="1"/>
+            <!-- child elements are appended by JS -->
+        </row>
+      </rows>
+    </grid>
+    <spacer class="spacer"/>
+  </groupbox>
+  <spacer class="spacer"/>
+  <hbox align="center">
+    <label control="borderInput" class="align-right"
+        value="&borderEditField.label;"
+        accesskey="&borderEditField.accessKey;"
+        tooltiptext="&borderEditField.tooltip;" />
+    <textbox class="narrow" id="borderInput" oninput="forceInteger(this.id)" />
+    <label value="&pixels.label;"/>  
+  </hbox>
+  <!-- from EdDialogOverlay -->
+  <vbox id="AdvancedEdit"/>
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdLabelProps.js
@@ -0,0 +1,144 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Label Properties Dialog.
+ *
+ * The Initial Developer of the Original Code is
+ * Neil Rashbrook.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s): Neil Rashbrook <neil@parkwaycc.co.uk>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var labelElement;
+
+// dialog initialization code
+
+function Startup()
+{
+  var editor = GetCurrentEditor();
+  if (!editor)
+  {
+    dump("Failed to get active editor!\n");
+    window.close();
+    return;
+  }
+
+  gDialog.editText = document.getElementById("EditText");
+  gDialog.labelText = document.getElementById("LabelText");
+  gDialog.labelFor = document.getElementById("LabelFor");
+  gDialog.labelAccessKey = document.getElementById("LabelAccessKey");
+
+  labelElement = window.arguments[0];
+
+  // Make a copy to use for AdvancedEdit
+  globalElement = labelElement.cloneNode(false);
+
+  InitDialog();
+
+  var range = editor.document.createRange();
+  range.selectNode(labelElement);
+  gDialog.labelText.value = range.toString();
+
+  if (/</.test(labelElement.innerHTML))
+  {
+    gDialog.editText.checked = false;
+    gDialog.editText.disabled = false;
+    gDialog.labelText.disabled = true;
+    gDialog.editText.addEventListener("command", onEditText, false);
+    SetTextboxFocus(gDialog.labelFor);
+  }
+  else
+    SetTextboxFocus(gDialog.labelText);
+
+  SetWindowLocation();
+}
+
+function InitDialog()
+{
+  gDialog.labelFor.value = globalElement.getAttribute("for");
+  gDialog.labelAccessKey.value = globalElement.getAttribute("accesskey");
+}
+
+function onEditText()
+{
+  gDialog.editText.removeEventListener("command", onEditText, false);
+  AlertWithTitle(GetString("Alert"), GetString("EditTextWarning"));
+}
+
+function RemoveLabel()
+{
+  RemoveContainer(labelElement);
+  SaveWindowLocation();
+  window.close();
+}
+
+function ValidateData()
+{
+  if (gDialog.labelFor.value)
+    globalElement.setAttribute("for", gDialog.labelFor.value);
+  else
+    globalElement.removeAttribute("for");
+  if (gDialog.labelAccessKey.value)
+    globalElement.setAttribute("accesskey", gDialog.labelAccessKey.value);
+  else
+    globalElement.removeAttribute("accesskey");
+  return true;
+}
+
+function onAccept()
+{
+  // All values are valid - copy to actual element in doc
+  ValidateData();
+
+  var editor = GetCurrentEditor();
+
+  editor.beginTransaction();
+
+  try {
+    if (gDialog.editText.checked)
+    {
+      editor.setShouldTxnSetSelection(false);
+
+      while (labelElement.firstChild)
+        editor.deleteNode(labelElement.firstChild);
+      if (gDialog.labelText.value)
+        editor.insertNode(editor.document.createTextNode(gDialog.labelText.value), labelElement, 0);
+
+      editor.setShouldTxnSetSelection(true);
+    }
+
+    editor.cloneAttributes(labelElement, globalElement);
+  } catch(e) {}
+
+  editor.endTransaction();
+
+  SaveWindowLocation();
+
+  return true;
+}
+
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdLabelProps.xul
@@ -0,0 +1,90 @@
+<?xml version="1.0"?>
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Label Properties Dialog.
+   -
+   - The Initial Developer of the Original Code is
+   - Neil Rashbrook.
+   - Portions created by the Initial Developer are Copyright (C) 2001
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s): Neil Rashbrook <neil@parkwaycc.co.uk>
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either the GNU General Public License Version 2 or later (the "GPL"), or
+   - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the LGPL or the GPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?> 
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorLabelProperties.dtd">
+<dialog title="&windowTitle.label;"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        onload="Startup();"
+        buttons="accept,cancel"
+        ondialogaccept="return onAccept();"
+        ondialogcancel="return onCancel();">
+
+  <!-- Methods common to all editor dialogs -->
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdLabelProps.js"/>
+
+  <broadcaster id="args" value=""/>
+  <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+  <groupbox><caption label="&Settings.label;" accesskey="&Settings.accesskey;"/>
+    <grid><columns><column/><column/></columns>
+      <rows>
+        <row align="center">
+          <checkbox id="EditText" label="&EditLabelText.label;" accesskey="&EditLabelText.accesskey;" checked="true" disabled="true"
+            oncommand="gDialog.labelText.disabled = !gDialog.editText.checked;"/>
+          <textbox id="LabelText" accesskey="&Settings.accesskey;"/>
+        </row>
+        <row align="center">
+          <label control="LabelFor" value="&LabelFor.label;" accesskey="&LabelFor.accesskey;"/>
+          <textbox id="LabelFor"/>
+        </row>
+        <row align="center">
+          <label control="LabelAccessKey" value="&AccessKey.label;" accesskey="&AccessKey.accesskey;"/>
+          <hbox>
+            <textbox id="LabelAccessKey" class="narrow"/>
+          </hbox>
+        </row>
+      </rows>
+    </grid>
+  </groupbox>
+
+  <!-- from EdDialogOverlay -->
+  <hbox flex="1" style="margin-top: 0.2em">
+    <button id="RemoveLabel" label="&RemoveLabel.label;" accesskey="&RemoveLabel.accesskey;" oncommand="RemoveLabel();"/>
+    <!-- This will right-align the button -->
+    <spacer flex="1"/>
+    <button id="AdvancedEditButton"/>
+  </hbox>
+  <separator class="groove"/>
+
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdLinkChecker.js
@@ -0,0 +1,234 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Akkana Peck (akkana@netscape.com)
+ *   Charles Manxke (cmanske@netscape.com)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// Variables used across all the links being checked:
+var gNumLinksToCheck = 0;     // The number of nsILinkCheckers
+var gLinksBeingChecked = [];  // Array of nsIURICheckers
+var gURIRefObjects = [];      // Array of nsIURIRefObjects
+var gNumLinksCalledBack = 0;
+var gStartedAllChecks = false;
+var gLinkCheckTimerID = 0;
+
+// Implement nsIRequestObserver:
+var gRequestObserver =
+{
+  // urichecker requires that we have an OnStartRequest even tho it's a nop.
+  onStartRequest: function(request, ctxt) { },
+
+  // onStopRequest is where we really handle the status.
+  onStopRequest: function(request, ctxt, status)
+  {
+    var linkChecker = request.QueryInterface(Components.interfaces.nsIURIChecker);
+    if (linkChecker)
+    {
+      gNumLinksCalledBack++;
+      linkChecker.status = status;
+      for (var i = 0; i < gNumLinksCalledBack; i++)
+      {
+        if (linkChecker == gLinksBeingChecked[i])
+          gLinksBeingChecked[i].status = status;
+      }
+
+      if (gStartedAllChecks && gNumLinksCalledBack >= gNumLinksToCheck)
+      {
+        clearTimeout(gLinkCheckTimerID);
+        LinkCheckTimeOut();
+      }
+    }
+  }
+}
+
+function Startup()
+{
+  var editor = GetCurrentEditor();
+  if (!editor)
+  {
+    window.close();
+    return;
+  }
+
+  // Get all objects that refer to other locations
+  var objects;
+  try {
+    objects = editor.getLinkedObjects();
+  } catch (e) {}
+
+  if (!objects || objects.Count() == 0)
+  {
+    AlertWithTitle(GetString("Alert"), GetString("NoLinksToCheck"));
+    window.close();
+    return;
+  }
+
+  gDialog.LinksList = document.getElementById("LinksList");
+
+  // Set window location relative to parent window (based on persisted attributes)
+  SetWindowLocation();
+
+
+  // Loop over the nodes that have links:
+  for (var i = 0; i < objects.Count(); i++)
+  {
+    var refobj = objects.GetElementAt(gNumLinksToCheck).QueryInterface(Components.interfaces.nsIURIRefObject);
+    // Loop over the links in this node:
+    if (refobj)
+    {
+      try {
+        var uri;
+        while ((uri = refobj.GetNextURI()))
+        {
+          // Use the real class in netlib:
+          // Note that there may be more than one link per refobj
+          gURIRefObjects[gNumLinksToCheck] = refobj;
+
+          // Make a new nsIURIChecker
+          gLinksBeingChecked[gNumLinksToCheck]
+            = Components.classes["@mozilla.org/network/urichecker;1"]
+                .createInstance()
+                  .QueryInterface(Components.interfaces.nsIURIChecker);
+          // XXX uri creation needs to be localized
+          gLinksBeingChecked[gNumLinksToCheck].init(GetIOService().newURI(uri, null, null));
+          gLinksBeingChecked[gNumLinksToCheck].asyncCheck(gRequestObserver, null);
+
+          // Add item  
+          var linkChecker = gLinksBeingChecked[gNumLinksToCheck].QueryInterface(Components.interfaces.nsIURIChecker);
+          SetItemStatus(linkChecker.name, "busy");
+dump(" *** Linkcount = "+gNumLinksToCheck+"\n");
+          gNumLinksToCheck++;
+
+        };
+      } catch (e) { dump (" *** EXCEPTION\n");}
+    }
+  }
+  // Done with the loop, now we can be prepared for the finish:
+  gStartedAllChecks = true;
+
+  // Start timer to limit how long we wait for link checking
+  gLinkCheckTimerID = setTimeout("LinkCheckTimeOut()", 5000);
+  window.sizeToContent();
+}
+
+function LinkCheckTimeOut()
+{
+  // We might have gotten here via a late timeout
+  if (gNumLinksToCheck <= 0)
+    return;
+  gLinkCheckTimerID = 0;
+
+  gNumLinksToCheck = 0;
+  gStartedAllChecks = false;
+  for (var i=0; i < gLinksBeingChecked.length; i++)
+  {
+    var linkChecker = gLinksBeingChecked[i].QueryInterface(Components.interfaces.nsIURIChecker);
+    // nsIURIChecker status values:
+    // NS_BINDING_SUCCEEDED     link is valid
+    // NS_BINDING_FAILED        link is invalid (gave an error)
+    // NS_BINDING_ABORTED       timed out, or cancelled
+    switch (linkChecker.status)
+    {
+      case 0:           // NS_BINDING_SUCCEEDED
+        SetItemStatus(linkChecker.name, "done");
+        break;
+      case 0x804b0001:  // NS_BINDING_FAILED
+        dump(">> " + linkChecker.name + " is broken\n");
+      case 0x804b0002:   // NS_BINDING_ABORTED
+//        dump(">> " + linkChecker.name + " timed out\n");
+      default:
+//        dump(">> " + linkChecker.name + " not checked\n");
+        SetItemStatus(linkChecker.name, "failed");
+        break;
+    }
+  }
+}
+
+// Add url to list of links to check
+// or set status for file already in the list
+// Returns true if url was in the list
+function SetItemStatus(url, status)
+{
+  if (!url)
+    return false;
+
+  if (!status)
+    status = "busy";
+
+  // Just set attribute for status icon 
+  // if we already have this url 
+  var listitems = document.getElementsByTagName("listitem");
+  if (listitems)
+  {
+    for (var i=0; i < listitems.length; i++)
+    {
+      if (listitems[i].getAttribute("label") == url)
+      {
+        listitems[i].setAttribute("progress", status);
+        return true;
+      }
+    }
+  }
+
+  // We're adding a new item to list
+  var listitem = document.createElementNS(XUL_NS, "listitem");
+  if (listitem)
+  {
+    listitem.setAttribute("class", "listitem-iconic progressitem");
+    // This triggers CSS to show icon for each status state
+    listitem.setAttribute("progress", status);
+    listitem.setAttribute("label", url);
+    gDialog.LinksList.appendChild(listitem);
+  }
+  return false;
+}
+
+function onAccept()
+{
+  SaveWindowLocation();
+  return true; // do close the window
+}
+
+function onCancelLinkChecker()
+{
+  if (gLinkCheckTimerID)
+    clearTimeout(gLinkCheckTimerID);
+
+/*
+  LinkCheckTimeOut();
+*/
+  return onCancel();
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdLinkChecker.xul
@@ -0,0 +1,73 @@
+<?xml version="1.0"?>
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -   Charles Manske (cmanske@netscape.com)
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?> 
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EdLinkChecker.dtd">
+<!-- dialog containing a control requiring initial setup -->
+<dialog title="&windowTitle.label;"
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    onload="Startup()"
+    buttonlabelcancel="&closeButton.label;"
+    ondialogaccept="return onAccept();"
+    ondialogcancel="return onCancelLinkChecker();">
+
+  <!-- Methods common to all editor dialogs -->
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdLinkChecker.js"/>
+
+  <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+  <broadcaster id="args" value=""/>
+
+  <listbox rows="8" id="LinksList" class="MinWidth20" flex="1"/>
+  <hbox align="center">
+    <spacer class="bigspacer"/>
+    <image class="progressitem" progress="done"/>
+    <label value="&succeeded.label;"/>
+    <spacer class="bigspacer"/>
+    <spacer class="bigspacer"/>
+    <image class="progressitem" progress="failed"/>
+    <label value="&failed.label;"/>
+  </hbox>
+  <separator class="groove"/>
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdLinkProps.js
@@ -0,0 +1,375 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Charles Manske (cmanske@netscape.com)
+ *   Neil Rashbrook (neil@parkwaycc.co.uk)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var gActiveEditor;
+var anchorElement = null;
+var imageElement = null;
+var insertNew = false;
+var replaceExistingLink = false;
+var insertLinkAtCaret;
+var needLinkText = false;
+var href;
+var newLinkText;
+var gHNodeArray = {};
+var gHaveNamedAnchors = false;
+var gHaveHeadings = false;
+var gCanChangeHeadingSelected = true;
+var gCanChangeAnchorSelected = true;
+var gHaveDocumentUrl = false;
+
+// NOTE: Use "href" instead of "a" to distinguish from Named Anchor
+// The returned node is has an "a" tagName
+var tagName = "href";
+
+// dialog initialization code
+function Startup()
+{
+  gActiveEditor = GetCurrentEditor();
+  if (!gActiveEditor)
+  {
+    dump("Failed to get active editor!\n");
+    window.close();
+    return;
+  }
+  // Message was wrapped in a <label> or <div>, so actual text is a child text node
+  gDialog.linkTextCaption     = document.getElementById("linkTextCaption");
+  gDialog.linkTextMessage     = document.getElementById("linkTextMessage");
+  gDialog.linkTextInput       = document.getElementById("linkTextInput");
+  gDialog.hrefInput           = document.getElementById("hrefInput");
+  gDialog.makeRelativeLink    = document.getElementById("MakeRelativeLink");
+  gDialog.AdvancedEditSection = document.getElementById("AdvancedEdit");
+
+  // See if we have a single selected image
+  imageElement = gActiveEditor.getSelectedElement("img");
+
+  if (imageElement)
+  {
+    // Get the parent link if it exists -- more efficient than GetSelectedElement()
+    anchorElement = gActiveEditor.getElementOrParentByTagName("href", imageElement);
+    if (anchorElement)
+    {
+      if (anchorElement.childNodes.length > 1)
+      {
+        // If there are other children, then we want to break
+        //  this image away by inserting a new link around it,
+        //  so make a new node and copy existing attributes
+        anchorElement = anchorElement.cloneNode(false);
+        //insertNew = true;
+        replaceExistingLink = true;
+      }
+    }
+  }
+  else
+  {
+    // Get an anchor element if caret or
+    //   entire selection is within the link.
+    anchorElement = gActiveEditor.getSelectedElement(tagName);
+
+    if (anchorElement)
+    {
+      // Select the entire link
+      gActiveEditor.selectElement(anchorElement);
+    }
+    else
+    {
+      // If selection starts in a link, but extends beyond it,
+      //   the user probably wants to extend existing link to new selection,
+      //   so check if either end of selection is within a link
+      // POTENTIAL PROBLEM: This prevents user from selecting text in an existing
+      //   link and making 2 links. 
+      // Note that this isn't a problem with images, handled above
+
+      anchorElement = gActiveEditor.getElementOrParentByTagName("href", gActiveEditor.selection.anchorNode);
+      if (!anchorElement)
+        anchorElement = gActiveEditor.getElementOrParentByTagName("href", gActiveEditor.selection.focusNode);
+
+      if (anchorElement)
+      {
+        // But clone it for reinserting/merging around existing
+        //   link that only partially overlaps the selection
+        anchorElement = anchorElement.cloneNode(false);
+        //insertNew = true;
+        replaceExistingLink = true;
+      }
+    }
+  }
+
+  if(!anchorElement)
+  {
+    // No existing link -- create a new one
+    anchorElement = gActiveEditor.createElementWithDefaults(tagName);
+    insertNew = true;
+    // Hide message about removing existing link
+    //document.getElementById("RemoveLinkMsg").hidden = true;
+  }
+  if(!anchorElement)
+  {
+    dump("Failed to get selected element or create a new one!\n");
+    window.close();
+    return;
+  } 
+
+  // We insert at caret only when nothing is selected
+  insertLinkAtCaret = gActiveEditor.selection.isCollapsed;
+  
+  var selectedText;
+  if (insertLinkAtCaret)
+  {
+    // Groupbox caption:
+    gDialog.linkTextCaption.setAttribute("label", GetString("LinkText"));
+
+    // Message above input field:
+    gDialog.linkTextMessage.setAttribute("value", GetString("EnterLinkText"));
+    gDialog.linkTextMessage.setAttribute("accesskey", GetString("EnterLinkTextAccessKey"));
+  }
+  else
+  {
+    if (!imageElement)
+    {
+      // We get here if selection is exactly around a link node
+      // Check if selection has some text - use that first
+      selectedText = GetSelectionAsText();
+      if (!selectedText) 
+      {
+        // No text, look for first image in the selection
+        var children = anchorElement.childNodes;
+        if (children)
+        {
+          for(var i=0; i < children.length; i++) 
+          {
+            var nodeName = children.item(i).nodeName.toLowerCase();
+            if (nodeName == "img")
+            {
+              imageElement = children.item(i);
+              break;
+            }
+          }
+        }
+      }
+    }
+    // Set "caption" for link source and the source text or image URL
+    if (imageElement)
+    {
+      gDialog.linkTextCaption.setAttribute("label", GetString("LinkImage"));
+      // Link source string is the source URL of image
+      // TODO: THIS DOESN'T HANDLE MULTIPLE SELECTED IMAGES!
+      gDialog.linkTextMessage.setAttribute("value", imageElement.src);
+    } else {
+      gDialog.linkTextCaption.setAttribute("label", GetString("LinkText"));
+      if (selectedText) 
+      {
+        // Use just the first 60 characters and add "..."
+        gDialog.linkTextMessage.setAttribute("value", TruncateStringAtWordEnd(ReplaceWhitespace(selectedText, " "), 60, true));
+      } else {
+        gDialog.linkTextMessage.setAttribute("value", GetString("MixedSelection"));
+      }
+    }
+  }
+
+  // Make a copy to use for AdvancedEdit and onSaveDefault
+  globalElement = anchorElement.cloneNode(false);
+
+  // Get the list of existing named anchors and headings
+  FillLinkMenulist(gDialog.hrefInput, gHNodeArray);
+
+  // We only need to test for this once per dialog load
+  gHaveDocumentUrl = GetDocumentBaseUrl();
+
+  // Set data for the dialog controls
+  InitDialog();
+  
+  // Search for a URI pattern in the selected text
+  //  as candidate href
+  selectedText = TrimString(selectedText); 
+  if (!gDialog.hrefInput.value && TextIsURI(selectedText))
+      gDialog.hrefInput.value = selectedText;
+
+  // Set initial focus
+  if (insertLinkAtCaret) {
+    // We will be using the HREF inputbox, so text message
+    SetTextboxFocus(gDialog.linkTextInput);
+  } else {
+    SetTextboxFocus(gDialog.hrefInput);
+
+    // We will not insert a new link at caret, so remove link text input field
+    gDialog.linkTextInput.hidden = true;
+    gDialog.linkTextInput = null;
+  }
+    
+  // This sets enable state on OK button
+  doEnabling();
+
+  SetWindowLocation();
+}
+
+// Set dialog widgets with attribute data
+// We get them from globalElement copy so this can be used
+//   by AdvancedEdit(), which is shared by all property dialogs
+function InitDialog()
+{
+  // Must use getAttribute, not "globalElement.href", 
+  //  or foreign chars aren't coverted correctly!
+  gDialog.hrefInput.value = globalElement.getAttribute("href");
+
+  // Set "Relativize" checkbox according to current URL state
+  SetRelativeCheckbox(gDialog.makeRelativeLink);
+}
+
+function doEnabling()
+{
+  // We disable Ok button when there's no href text only if inserting a new link
+  var enable = insertNew ? (TrimString(gDialog.hrefInput.value).length > 0) : true;
+  
+  // anon. content, so can't use SetElementEnabledById here
+  var dialogNode = document.getElementById("linkDlg");
+  dialogNode.getButton("accept").disabled = !enable;
+
+  SetElementEnabledById( "AdvancedEditButton1", enable);
+}
+
+function ChangeLinkLocation()
+{
+  SetRelativeCheckbox(gDialog.makeRelativeLink);
+  // Set OK button enable state
+  doEnabling();
+}
+
+// Get and validate data from widgets.
+// Set attributes on globalElement so they can be accessed by AdvancedEdit()
+function ValidateData()
+{
+  href = TrimString(gDialog.hrefInput.value);
+  if (href)
+  {
+    // Set the HREF directly on the editor document's anchor node
+    //  or on the newly-created node if insertNew is true
+    globalElement.setAttribute("href",href);
+  }
+  else if (insertNew)
+  {
+    // We must have a URL to insert a new link
+    //NOTE: We accept an empty HREF on existing link to indicate removing the link
+    ShowInputErrorMessage(GetString("EmptyHREFError"));
+    return false;
+  }
+  if (gDialog.linkTextInput)
+  {
+    // The text we will insert isn't really an attribute,
+    //  but it makes sense to validate it
+    newLinkText = TrimString(gDialog.linkTextInput.value);
+    if (!newLinkText)
+    {
+      if (href)
+        newLinkText = href
+      else
+      {
+        ShowInputErrorMessage(GetString("EmptyLinkTextError"));
+        SetTextboxFocus(gDialog.linkTextInput);
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+function onAccept()
+{
+  if (ValidateData())
+  {
+    if (href.length > 0)
+    {
+      // Copy attributes to element we are changing or inserting
+      gActiveEditor.cloneAttributes(anchorElement, globalElement);
+
+      // Coalesce into one undo transaction
+      gActiveEditor.beginTransaction();
+
+      // Get text to use for a new link
+      if (insertLinkAtCaret)
+      {
+        // Append the link text as the last child node 
+        //   of the anchor node
+        var textNode = gActiveEditor.document.createTextNode(newLinkText);
+        if (textNode)
+          anchorElement.appendChild(textNode);
+        try {
+          gActiveEditor.insertElementAtSelection(anchorElement, false);
+        } catch (e) {
+          dump("Exception occured in InsertElementAtSelection\n");
+          return true;
+        }
+      } else if (insertNew || replaceExistingLink)
+      {
+        //  Link source was supplied by the selection,
+        //  so insert a link node as parent of this
+        //  (may be text, image, or other inline content)
+        try {
+          gActiveEditor.insertLinkAroundSelection(anchorElement);
+        } catch (e) {
+          dump("Exception occured in InsertElementAtSelection\n");
+          return true;
+        }
+      }
+      // Check if the link was to a heading 
+      if (href in gHNodeArray)
+      {
+        var anchorNode = gActiveEditor.createElementWithDefaults("a");
+        if (anchorNode)
+        {
+          anchorNode.name = href.substr(1);
+
+          // Insert the anchor into the document, 
+          //  but don't let the transaction change the selection
+          gActiveEditor.setShouldTxnSetSelection(false);
+          gActiveEditor.insertNode(anchorNode, gHNodeArray[href], 0);
+          gActiveEditor.setShouldTxnSetSelection(true);
+        }
+      }
+      gActiveEditor.endTransaction();
+    } 
+    else if (!insertNew)
+    {
+      // We already had a link, but empty HREF means remove it
+      EditorRemoveTextProperty("href", "");
+    }
+    SaveWindowLocation();
+    return true;
+  }
+  return false;
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdLinkProps.xul
@@ -0,0 +1,77 @@
+<?xml version="1.0"?>
+
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<?xul-overlay href="chrome://global/content/globalOverlay.xul"?>
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?> 
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorLinkProperties.dtd">
+
+<dialog id="linkDlg" title="&windowTitle.label;"
+   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+   buttons="accept,cancel"
+   onload = "Startup()"
+   ondialogaccept="return onAccept();"
+   ondialogcancel="return onCancel();">
+
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdLinkProps.js"/>
+
+  <broadcaster id="args" value=""/>
+  <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+  <vbox style="min-width: 20em">
+    <groupbox><caption id="linkTextCaption"/>
+      <vbox>
+        <label id="linkTextMessage" control="linkTextInput"/>
+        <textbox id="linkTextInput"/>
+      </vbox>
+    </groupbox>
+
+    <groupbox id="LinkURLBox"><caption label="&LinkURLBox.label;"/>
+      <vbox id="LinkLocationBox"/>
+      <!-- mail compose will insert custom item here defined in mailComposeEditorOverlay.xul -->
+    </groupbox>
+  </vbox>
+  <!-- from EdDialogOverlay -->
+  <vbox id="AdvancedEdit"/>
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdListProps.js
@@ -0,0 +1,478 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Charles Manske (cmanske@netscape.com)
+ *   Ryan Cassin (rcassin@supernova.org)
+ *   David Turley (dturley@pobox.com) contributed Roman Numeral conversion code.
+ *   Neil Rashbrook <neil@parkwaycc.co.uk>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+//Cancel() is in EdDialogCommon.js
+var gBulletStyleType = "";
+var gNumberStyleType = "";
+var gListElement;
+var gOriginalListType = "";
+var gListType = "";
+var gMixedListSelection = false;
+var gStyleType = "";
+var gOriginalStyleType = "";
+const gOnesArray = ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"];
+const gTensArray = ["", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"];
+const gHundredsArray = ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"];
+const gThousandsArray = ["", "M", "MM", "MMM", "MMMM", "MMMMM", "MMMMMM", "MMMMMMM", "MMMMMMMM", "MMMMMMMMM"];
+const gRomanDigits = {I: 1, V: 5, X: 10, L: 50, C: 100, D: 500, M: 1000};
+const A = "A".charCodeAt(0);
+const gArabic = "1";
+const gUpperRoman = "I";
+const gLowerRoman = "i";
+const gUpperLetters = "A";
+const gLowerLetters = "a";
+const gDecimalCSS = "decimal";
+const gUpperRomanCSS = "upper-roman";
+const gLowerRomanCSS = "lower-roman";
+const gUpperAlphaCSS = "upper-alpha";
+const gLowerAlphaCSS = "lower-alpha";
+
+// dialog initialization code
+function Startup()
+{
+  var editor = GetCurrentEditor();
+  if (!editor)
+  {
+    window.close();
+    return;
+  }
+  gDialog.ListTypeList = document.getElementById("ListType");
+  gDialog.BulletStyleList = document.getElementById("BulletStyle");
+  gDialog.BulletStyleLabel = document.getElementById("BulletStyleLabel");
+  gDialog.StartingNumberInput = document.getElementById("StartingNumber");
+  gDialog.StartingNumberLabel = document.getElementById("StartingNumberLabel");
+  gDialog.AdvancedEditButton = document.getElementById("AdvancedEditButton1");
+  gDialog.RadioGroup = document.getElementById("RadioGroup");
+  gDialog.ChangeAllRadio = document.getElementById("ChangeAll");
+  gDialog.ChangeSelectedRadio = document.getElementById("ChangeSelected");
+  
+  // Try to get an existing list(s)
+  var mixedObj = { value: null };
+  try {
+    gListType = editor.getListState(mixedObj, {}, {}, {} );
+
+    // We may have mixed list and non-list, or > 1 list type in selection
+    gMixedListSelection = mixedObj.value;
+
+    // Get the list element at the anchor node
+    gListElement = editor.getElementOrParentByTagName("list", null);
+  } catch (e) {}
+
+  // The copy to use in AdvancedEdit
+  if (gListElement)
+    globalElement = gListElement.cloneNode(false);
+
+  // Show extra options for changing entire list if we have one already.
+  gDialog.RadioGroup.collapsed = !gListElement;
+  if (gListElement)
+  {
+    // Radio button index is persistent
+    if (gDialog.RadioGroup.getAttribute("index") == "1")
+      gDialog.RadioGroup.selectedItem = gDialog.ChangeSelectedRadio;
+    else
+      gDialog.RadioGroup.selectedItem = gDialog.ChangeAllRadio;
+  }
+
+  InitDialog();
+
+  gOriginalListType = gListType;
+
+  gDialog.ListTypeList.focus();
+
+  SetWindowLocation();
+}
+
+function InitDialog()
+{
+  // Note that if mixed, we we pay attention 
+  //   only to the anchor node's list type
+  // (i.e., don't confuse user with "mixed" designation)
+  if (gListElement)
+    gListType = gListElement.nodeName.toLowerCase();
+  else
+    gListType = "";
+  
+  gDialog.ListTypeList.value = gListType;
+  gDialog.StartingNumberInput.value = "";
+  
+  // Last param = true means attribute value is case-sensitive
+  var type = globalElement ? GetHTMLOrCSSStyleValue(globalElement, "type", "list-style-type") : null;
+
+  var index = 0;
+  if (gListType == "ul")
+  {
+    if (type)
+    {
+      type = type.toLowerCase();
+      gBulletStyleType = type;
+      gOriginalStyleType = type;
+    }
+  }
+  else if (gListType == "ol")
+  {
+    // Translate CSS property strings
+    switch (type.toLowerCase())
+    {
+      case gDecimalCSS:
+        type = gArabic;
+        break;
+      case gUpperRomanCSS:
+        type = gUpperRoman;
+        break;
+      case gLowerRomanCSS:
+        type = gLowerRoman;
+        break;
+      case gUpperAlphaCSS:
+        type = gUpperLetters;
+        break;
+      case gLowerAlphaCSS:
+        type = gLowerLetters;
+        break;
+    }
+    if (type)
+    {
+      gNumberStyleType = type;
+      gOriginalStyleType = type;
+    }
+
+    // Convert attribute number to appropriate letter or roman numeral
+    gDialog.StartingNumberInput.value = 
+      ConvertStartAttrToUserString(globalElement.getAttribute("start"), type);
+  }
+  BuildBulletStyleList();
+}
+
+// Convert attribute number to appropriate letter or roman numeral
+function ConvertStartAttrToUserString(startAttr, type)
+{
+  switch (type)
+  {
+    case gUpperRoman:
+      startAttr = ConvertArabicToRoman(startAttr);
+      break;
+    case gLowerRoman:
+      startAttr = ConvertArabicToRoman(startAttr).toLowerCase();
+      break;
+    case gUpperLetters:
+      startAttr = ConvertArabicToLetters(startAttr);
+      break;
+    case gLowerLetters:
+      startAttr = ConvertArabicToLetters(startAttr).toLowerCase();
+      break;
+  }
+  return startAttr;
+}
+
+function BuildBulletStyleList()
+{
+  gDialog.BulletStyleList.removeAllItems();
+  var label;
+
+  if (gListType == "ul")
+  {
+    gDialog.BulletStyleList.removeAttribute("disabled");
+    gDialog.BulletStyleLabel.removeAttribute("disabled");
+    gDialog.StartingNumberInput.setAttribute("disabled", "true");
+    gDialog.StartingNumberLabel.setAttribute("disabled", "true");
+
+    label = GetString("BulletStyle");
+
+    gDialog.BulletStyleList.appendItem(GetString("Automatic"), "");
+    gDialog.BulletStyleList.appendItem(GetString("SolidCircle"), "disc");
+    gDialog.BulletStyleList.appendItem(GetString("OpenCircle"), "circle");
+    gDialog.BulletStyleList.appendItem(GetString("SolidSquare"), "square");
+
+    gDialog.BulletStyleList.value = gBulletStyleType;
+  }
+  else if (gListType == "ol")
+  {
+    gDialog.BulletStyleList.removeAttribute("disabled");
+    gDialog.BulletStyleLabel.removeAttribute("disabled");
+    gDialog.StartingNumberInput.removeAttribute("disabled");
+    gDialog.StartingNumberLabel.removeAttribute("disabled");
+    label = GetString("NumberStyle");
+
+    gDialog.BulletStyleList.appendItem(GetString("Automatic"), "");
+    gDialog.BulletStyleList.appendItem(GetString("Style_1"), gArabic);
+    gDialog.BulletStyleList.appendItem(GetString("Style_I"), gUpperRoman);
+    gDialog.BulletStyleList.appendItem(GetString("Style_i"), gLowerRoman);
+    gDialog.BulletStyleList.appendItem(GetString("Style_A"), gUpperLetters);
+    gDialog.BulletStyleList.appendItem(GetString("Style_a"), gLowerLetters);
+
+    gDialog.BulletStyleList.value = gNumberStyleType;
+  } 
+  else 
+  {
+    gDialog.BulletStyleList.setAttribute("disabled", "true");
+    gDialog.BulletStyleLabel.setAttribute("disabled", "true");
+    gDialog.StartingNumberInput.setAttribute("disabled", "true");
+    gDialog.StartingNumberLabel.setAttribute("disabled", "true");
+  }
+  
+  // Disable advanced edit button if changing to "normal"
+  if (gListType)
+    gDialog.AdvancedEditButton.removeAttribute("disabled");
+  else
+    gDialog.AdvancedEditButton.setAttribute("disabled", "true");
+
+  if (label)
+    gDialog.BulletStyleLabel.setAttribute("label",label);
+}
+
+function SelectListType()
+{
+  // Each list type is stored in the "value" of each menuitem
+  var NewType = gDialog.ListTypeList.value;
+
+  if (NewType == "ol")
+    SetTextboxFocus(gDialog.StartingNumberInput);
+
+  if (gListType != NewType)
+  {
+    gListType = NewType;
+    
+    // Create a newlist object for Advanced Editing
+    try {
+      if (gListType)
+        globalElement = GetCurrentEditor().createElementWithDefaults(gListType);
+    } catch (e) {}
+
+    BuildBulletStyleList();
+  }
+}
+
+function SelectBulletStyle()
+{
+  // Save the selected index so when user changes
+  //   list style, restore index to associated list
+  // Each bullet or number type is stored in the "value" of each menuitem
+  if (gListType == "ul")
+    gBulletStyleType = gDialog.BulletStyleList.value;
+  else if (gListType == "ol")
+  {
+    var type = gDialog.BulletStyleList.value;
+    if (gNumberStyleType != type)
+    {
+      // Convert existing input value to attr number first,
+      //   then convert to the appropriate format for the newly-selected
+      gDialog.StartingNumberInput.value = 
+        ConvertStartAttrToUserString( ConvertUserStringToStartAttr(gNumberStyleType), type);
+
+      gNumberStyleType = type;
+      SetTextboxFocus(gDialog.StartingNumberInput);
+    }
+  }
+}
+
+function ValidateData()
+{
+  gBulletStyleType = gDialog.BulletStyleList.value;
+  // globalElement should already be of the correct type 
+
+  if (globalElement)
+  {
+    var editor = GetCurrentEditor();
+    if (gListType == "ul")
+    {
+      if (gBulletStyleType && gDialog.ChangeAllRadio.selected)
+        globalElement.setAttribute("type", gBulletStyleType);
+      else
+        try {
+          editor.removeAttributeOrEquivalent(globalElement, "type", true);
+        } catch (e) {}
+
+    } 
+    else if (gListType == "ol")
+    {
+      if (gBulletStyleType)
+        globalElement.setAttribute("type", gBulletStyleType);
+      else
+        try {
+          editor.removeAttributeOrEquivalent(globalElement, "type", true);
+        } catch (e) {}
+      
+      var startingNumber = ConvertUserStringToStartAttr(gBulletStyleType);
+      if (startingNumber)
+        globalElement.setAttribute("start", startingNumber);
+      else
+        globalElement.removeAttribute("start");
+    }
+  }
+  return true;
+}
+
+function ConvertUserStringToStartAttr(type)
+{
+  var startingNumber = TrimString(gDialog.StartingNumberInput.value);
+
+  switch (type)
+  {
+    case gUpperRoman:
+    case gLowerRoman:
+      // If the input isn't an integer, assume it's a roman numeral. Convert it.
+      if (!Number(startingNumber))
+        startingNumber = ConvertRomanToArabic(startingNumber);
+      break;
+    case gUpperLetters:
+    case gLowerLetters:
+      // Get the number equivalent of the letters
+      if (!Number(startingNumber))
+        startingNumber = ConvertLettersToArabic(startingNumber);
+      break;
+  }
+  return startingNumber;
+}
+
+function ConvertRomanToArabic(num)
+{
+  num = num.toUpperCase();
+  if (num && !/[^MDCLXVI]/i.test(num))
+  {
+    var Arabic = 0;
+    var last_digit = 1000;
+    for (var i=0; i < num.length; i++)
+    {
+      var digit = gRomanDigits[num.charAt(i)];
+      if (last_digit < digit)
+        Arabic -= 2 * last_digit;
+
+      last_digit = digit;
+      Arabic += last_digit;
+    }
+    return Arabic;
+  }
+
+  return "";
+}
+
+function ConvertArabicToRoman(num)
+{
+  if (/^\d{1,4}$/.test(num))
+  {
+    var digits = ("000" + num).substr(-4);
+    return gThousandsArray[digits.charAt(0)] +
+           gHundredsArray[digits.charAt(1)] +
+           gTensArray[digits.charAt(2)] +
+           gOnesArray[digits.charAt(3)];
+  }
+  return "";
+}
+
+function ConvertLettersToArabic(letters)
+{
+  letters = letters.toUpperCase();
+  if (!letters || /[^A-Z]/.test(letters))
+    return "";
+
+  var num = 0;
+  for (var i = 0; i < letters.length; i++)
+    num = num * 26 + letters.charCodeAt(i) - A + 1;
+  return num;
+}
+
+function ConvertArabicToLetters(num)
+{
+  var letters = "";
+  while (num) {
+    num--;
+    letters = String.fromCharCode(A + (num % 26)) + letters;
+    num = Math.floor(num / 26);
+  }
+  return letters;
+}
+
+function onAccept()
+{
+  if (ValidateData())
+  {
+    // Coalesce into one undo transaction
+    var editor = GetCurrentEditor();
+
+    editor.beginTransaction();
+
+    var changeEntireList = gDialog.RadioGroup.selectedItem == gDialog.ChangeAllRadio;
+
+    // Remember which radio button was selected
+    if (gListElement)
+      gDialog.RadioGroup.setAttribute("index", changeEntireList ? "0" : "1");
+
+    var changeList;
+    if (gListElement && gDialog.ChangeAllRadio.selected)
+    {
+      changeList = true;
+    }
+    else
+      changeList = gMixedListSelection || gListType != gOriginalListType || 
+                   gBulletStyleType != gOriginalStyleType;
+    if (changeList)
+    {
+      try {
+        if (gListType)
+        {
+          editor.makeOrChangeList(gListType, changeEntireList,
+                     (gBulletStyleType != gOriginalStyleType) ? gBulletStyleType : null);
+
+          // Get the new list created:
+          gListElement = editor.getElementOrParentByTagName(gListType, null);
+
+          editor.cloneAttributes(gListElement, globalElement);
+        }
+        else
+        {
+          // Remove all existing lists
+          if (gListElement && changeEntireList)
+            editor.selectElement(gListElement);
+
+          editor.removeList("ol");
+          editor.removeList("ul");
+          editor.removeList("dl");
+        }
+      } catch (e) {}
+    }
+
+    editor.endTransaction();
+    
+    SaveWindowLocation();
+
+    return true;
+  }
+  return false;
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdListProps.xul
@@ -0,0 +1,95 @@
+<?xml version="1.0"?>
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -   Charles Manske (cmanske@netscape.com)
+   -   Ryan Cassin (rcassin@supernova.org)
+   -   Neil Rashbrook <neil@parkwaycc.co.uk>
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?> 
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorListProperties.dtd">
+<dialog title="&windowTitle.label;"
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    onload = "Startup()"
+    ondialogaccept="return onAccept();"
+    ondialogcancel="return onCancel();">
+
+  <!-- Methods common to all editor dialogs -->
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdListProps.js"/>
+
+  <broadcaster id="args" value=""/>
+  <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+  <groupbox flex="1"><caption label="&ListType.label;"/>
+    <menulist id="ListType" oncommand="SelectListType()">
+      <menupopup>
+        <menuitem label="&none.value;"/>
+        <menuitem value="ul" label="&bulletList.value;"/>
+        <menuitem value="ol" label="&numberList.value;"/>
+        <menuitem value="dl" label="&definitionList.value;"/>
+      </menupopup>
+    </menulist>
+  </groupbox>
+  <spacer class="spacer"/>
+
+  <!-- message text and list items are set in JS 
+       text value should be identical to string with id=BulletStyle in editor.properties 
+  -->
+  <groupbox flex="1"><caption id="BulletStyleLabel" label="&bulletStyle.label;"/>
+    <menulist class="MinWidth10em" id="BulletStyle" oncommand="SelectBulletStyle()">
+      <menupopup/>
+    </menulist>
+    <spacer class="spacer"/>
+    <hbox>
+      <label id="StartingNumberLabel" control="StartingNumber"
+             value="&startingNumber.label;" accesskey="&startingNumber.accessKey;"/>
+      <textbox class="narrow" id="StartingNumber"/>
+      <spacer/>
+    </hbox>
+  </groupbox>
+  <radiogroup id="RadioGroup" index="0" persist="index">
+    <radio id="ChangeAll"      label="&changeEntireListRadio.label;" accesskey="&changeEntireListRadio.accessKey;"/>
+    <radio id="ChangeSelected" label="&changeSelectedRadio.label;"   accesskey="&changeSelectedRadio.accessKey;"/>
+  </radiogroup>
+  <!-- from EdDialogOverlay -->
+  <vbox id="AdvancedEdit"/>
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdNamedAnchorProps.js
@@ -0,0 +1,197 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var gInsertNew = true;
+var gAnchorElement = null;
+var gOriginalName = "";
+const kTagName = "anchor";
+
+// dialog initialization code
+function Startup()
+{
+  var editor = GetCurrentEditor();
+  if (!editor)
+  {
+    window.close();
+    return;
+  }
+
+  gDialog.OkButton  = document.documentElement.getButton("accept");
+  gDialog.NameInput = document.getElementById("nameInput");
+
+  // Get a single selected element of the desired type
+  gAnchorElement = editor.getSelectedElement(kTagName);
+
+  if (gAnchorElement) {
+    // We found an element and don't need to insert one
+    gInsertNew = false;
+
+    // Make a copy to use for AdvancedEdit
+    globalElement = gAnchorElement.cloneNode(false);
+    gOriginalName = ConvertToCDATAString(gAnchorElement.name);
+  } else {
+    gInsertNew = true;
+    // We don't have an element selected, 
+    //  so create one with default attributes
+    gAnchorElement = editor.createElementWithDefaults(kTagName);
+    if (gAnchorElement) {
+      // Use the current selection as suggested name
+      var name = GetSelectionAsText();
+      // Get 40 characters of the selected text and don't add "...",
+      //  replace whitespace with "_" and strip non-word characters
+      name = ConvertToCDATAString(TruncateStringAtWordEnd(name, 40, false));
+      //Be sure the name is unique to the document
+      if (AnchorNameExists(name))
+        name += "_"
+
+      // Make a copy to use for AdvancedEdit
+      globalElement = gAnchorElement.cloneNode(false);
+      globalElement.setAttribute("name",name);
+    }
+  }
+  if(!gAnchorElement)
+  {
+    dump("Failed to get selected element or create a new one!\n");
+    window.close();
+    return;
+  }
+
+  InitDialog();
+  
+  DoEnabling();
+  SetTextboxFocus(gDialog.NameInput);
+  SetWindowLocation();
+}
+
+function InitDialog()
+{
+  gDialog.NameInput.value = globalElement.getAttribute("name");
+}
+
+function ChangeName()
+{
+  if (gDialog.NameInput.value.length > 0)
+  {
+    // Replace spaces with "_" and strip other non-URL characters
+    // Note: we could use ConvertAndEscape, but then we'd
+    //  have to UnEscapeAndConvert beforehand - too messy!
+    gDialog.NameInput.value = ConvertToCDATAString(gDialog.NameInput.value);
+  }
+  DoEnabling();
+}
+
+function DoEnabling()
+{
+  var enable = gDialog.NameInput.value.length > 0;
+  SetElementEnabled(gDialog.OkButton,  enable);
+  SetElementEnabledById("AdvancedEditButton1", enable);
+}
+
+function AnchorNameExists(name)
+{
+  var anchorList;
+  try {
+    anchorList = GetCurrentEditor().document.anchors;
+  } catch (e) {}
+
+  if (anchorList) {
+    for (var i = 0; i < anchorList.length; i++) {
+      if (anchorList[i].name == name)
+        return true;
+    }
+  }
+  return false;
+}
+
+// Get and validate data from widgets.
+// Set attributes on globalElement so they can be accessed by AdvancedEdit()
+function ValidateData()
+{
+  var name = TrimString(gDialog.NameInput.value);
+  if (!name)
+  {
+      ShowInputErrorMessage(GetString("MissingAnchorNameError"));
+      SetTextboxFocus(gDialog.NameInput);
+      return false;
+  } else {
+    // Replace spaces with "_" and strip other characters
+    // Note: we could use ConvertAndEscape, but then we'd
+    //  have to UnConverAndEscape beforehand - too messy!
+    name = ConvertToCDATAString(name);
+
+    if (gOriginalName != name && AnchorNameExists(name))
+    {
+      ShowInputErrorMessage(GetString("DuplicateAnchorNameError").replace(/%name%/,name));            
+      SetTextboxFocus(gDialog.NameInput);
+      return false;
+    }
+    globalElement.name = name;
+  }
+  return true;
+}
+
+function onAccept()
+{
+  if (ValidateData())
+  {
+    if (gOriginalName != globalElement.name)
+    {
+      var editor = GetCurrentEditor();
+      editor.beginTransaction();
+
+      try {
+        // "false" = don't delete selected text when inserting
+        if (gInsertNew)
+        {
+          // We must insert element before copying CSS style attribute,
+          //  but we must set the name else it won't insert at all
+          gAnchorElement.name = globalElement.name;
+          editor.insertElementAtSelection(gAnchorElement, false);
+        }
+
+        // Copy attributes to element we are changing or inserting
+        editor.cloneAttributes(gAnchorElement, globalElement);
+
+      } catch (e) {}
+
+      editor.endTransaction();
+    }
+    SaveWindowLocation();
+    return true;
+  }
+  return false;
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdNamedAnchorProps.xul
@@ -0,0 +1,68 @@
+<?xml version="1.0"?>
+
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?> 
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EdNamedAnchorProperties.dtd">
+
+<dialog title="&windowTitle.label;"
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    onload = "Startup()"
+    ondialogaccept="return onAccept();"
+    ondialogcancel="return onCancel();">
+
+  <!-- Methods common to all editor dialogs -->
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdNamedAnchorProps.js"/>
+
+  <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+  <label control="nameInput"
+         value="&anchorNameEditField.label;"
+         accesskey="&anchorNameEditField.accessKey;"/>
+  <textbox class="MinWidth20em" id="nameInput" oninput="ChangeName()" 
+             tooltiptext="&nameInput.tooltip;"/>
+  <spacer class="spacer"/>
+  <!-- from EdDialogOverlay -->
+  <vbox id="AdvancedEdit"/>
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdPageProps.js
@@ -0,0 +1,202 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Charles Manske (cmanske@netscape.com)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var gNewTitle = "";
+var gAuthor = "";
+var gDescription = "";
+var gAuthorElement;
+var gDescriptionElement;
+var gInsertNewAuthor = false;
+var gInsertNewDescription = false;
+var gTitleWasEdited = false;
+var gAuthorWasEdited = false;
+var gDescWasEdited = false;
+
+//Cancel() is in EdDialogCommon.js
+// dialog initialization code
+function Startup()
+{
+  var editor = GetCurrentEditor();
+  if (!editor)
+  {
+    window.close();
+    return;
+  }
+
+  gDialog.PageLocation     = document.getElementById("PageLocation");
+  gDialog.PageModDate      = document.getElementById("PageModDate");
+  gDialog.TitleInput       = document.getElementById("TitleInput");
+  gDialog.AuthorInput      = document.getElementById("AuthorInput");
+  gDialog.DescriptionInput = document.getElementById("DescriptionInput");
+  
+  // Default string for new page is set from DTD string in XUL,
+  //   so set only if not new doc URL
+  var location = GetDocumentUrl();
+  var lastmodString = GetString("Unknown");
+
+  if (!IsUrlAboutBlank(location))
+  {
+    // NEVER show username and password in clear text
+    gDialog.PageLocation.setAttribute("value", StripPassword(location));
+
+    // Get last-modified file date+time
+    // TODO: Convert this to local time?
+    var lastmod;
+    try {
+      lastmod = editor.document.lastModified;  // get string of last modified date
+    } catch (e) {}
+    // Convert modified string to date (0 = unknown date or January 1, 1970 GMT)
+    if(Date.parse(lastmod))
+    {
+      try {
+        const nsScriptableDateFormat_CONTRACTID = "@mozilla.org/intl/scriptabledateformat;1";
+        const nsIScriptableDateFormat = Components.interfaces.nsIScriptableDateFormat;
+        var dateService = Components.classes[nsScriptableDateFormat_CONTRACTID]
+         .getService(nsIScriptableDateFormat);
+
+        var lastModDate = new Date();
+        lastModDate.setTime(Date.parse(lastmod));
+        lastmodString =  dateService.FormatDateTime("", 
+                                      dateService.dateFormatLong,
+                                      dateService.timeFormatSeconds,
+                                      lastModDate.getFullYear(),
+                                      lastModDate.getMonth()+1,
+                                      lastModDate.getDate(),
+                                      lastModDate.getHours(),
+                                      lastModDate.getMinutes(),
+                                      lastModDate.getSeconds());
+      } catch (e) {}
+    }
+  }
+  gDialog.PageModDate.value = lastmodString;
+
+  gAuthorElement = GetMetaElement("author");
+  if (!gAuthorElement)
+  {
+    gAuthorElement = CreateMetaElement("author");
+    if (!gAuthorElement)
+    {
+      window.close();
+      return;
+    }
+    gInsertNewAuthor = true;
+  }
+
+  gDescriptionElement = GetMetaElement("description");
+  if (!gDescriptionElement)
+  {
+    gDescriptionElement = CreateMetaElement("description");
+    if (!gDescriptionElement)
+      window.close();
+
+    gInsertNewDescription = true;
+  }
+  
+  InitDialog();
+
+  SetTextboxFocus(gDialog.TitleInput);
+
+  SetWindowLocation();
+}
+
+function InitDialog()
+{
+  gDialog.TitleInput.value = GetDocumentTitle();
+
+  var gAuthor = TrimString(gAuthorElement.getAttribute("content"));
+  if (!gAuthor)
+  {
+    // Fill in with value from editor prefs
+    var prefs = GetPrefs();
+    if (prefs) 
+      gAuthor = prefs.getCharPref("editor.author");
+  }
+  gDialog.AuthorInput.value = gAuthor;
+  gDialog.DescriptionInput.value = gDescriptionElement.getAttribute("content");
+}
+
+function TextboxChanged(ID)
+{
+  switch(ID)
+  {
+    case "TitleInput":
+      gTitleWasEdited = true;
+      break;
+    case "AuthorInput":
+      gAuthorWasEdited = true;
+      break;
+    case "DescriptionInput":
+      gDescWasEdited = true;
+      break;
+  }
+}
+
+function ValidateData()
+{
+  gNewTitle = TrimString(gDialog.TitleInput.value);
+  gAuthor = TrimString(gDialog.AuthorInput.value);
+  gDescription = TrimString(gDialog.DescriptionInput.value);
+  return true;
+}
+
+function onAccept()
+{
+  if (ValidateData())
+  {
+    var editor = GetCurrentEditor();
+    editor.beginTransaction();
+
+    // Set title contents even if string is empty
+    //  because TITLE is a required HTML element
+    if (gTitleWasEdited)
+      SetDocumentTitle(gNewTitle);
+    
+    if (gAuthorWasEdited)
+      SetMetaElementContent(gAuthorElement, gAuthor, gInsertNewAuthor, false);
+
+    if (gDescWasEdited)
+      SetMetaElementContent(gDescriptionElement, gDescription, gInsertNewDescription, false);
+
+    editor.endTransaction();
+
+    SaveWindowLocation();
+    return true; // do close the window
+  }
+  return false;
+}
+
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdPageProps.xul
@@ -0,0 +1,90 @@
+<?xml version="1.0"?>
+
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?> 
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorPageProperties.dtd">
+
+<dialog title="&windowTitle.label;"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        onload="Startup();"
+        ondialogaccept="return onAccept();"
+        ondialogcancel="return onCancel();">
+
+  <!-- Methods common to all editor dialogs -->
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdPageProps.js"/>
+
+  <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+  <broadcaster id="args" value=""/>
+  <grid>
+    <columns><column flex="1"/><column flex="2"/></columns>
+    <rows>
+      <row>
+        <label value="&location.label;"/>
+        <label value="&locationNewPage.label;" id="PageLocation"/>
+      </row>
+      <row>
+        <label value="&lastModified.label;"/>
+        <label id="PageModDate"/>
+      </row>
+      <spacer class="spacer"/>
+      <row align="center">
+        <label value="&titleInput.label;" accesskey="&titleInput.accessKey;" control="TitleInput"/>
+        <textbox class="MinWidth20em" id="TitleInput" oninput="TextboxChanged(this.id)"/>
+      </row>
+      <row align="center">
+        <label value="&authorInput.label;" accesskey="&authorInput.accessKey;" control="AuthorInput"/>
+        <textbox class="MinWidth20em" id="AuthorInput" oninput="TextboxChanged(this.id)"/>
+      </row>
+      <row align="center">
+        <label value="&descriptionInput.label;" accesskey="&descriptionInput.accessKey;" control="DescriptionInput"/>
+        <textbox class="MinWidth20em" id="DescriptionInput" oninput="TextboxChanged(this.id)"/>
+      </row>
+    </rows>
+  </grid>
+  <spacer class="bigspacer"/>
+  <label value="&EditHEADSource1.label;"/>
+  <description class="wrap" flex="1">&EditHEADSource2.label;</description>
+  <separator class="groove"/>
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdReplace.js
@@ -0,0 +1,415 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Kin Blas <kin@netscape.com>
+ *   Akkana Peck <akkana@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var gReplaceDialog;      // Quick access to document/form elements.
+var gFindInst;           // nsIWebBrowserFind that we're going to use
+var gFindService;        // Global service which remembers find params
+var gEditor;             // the editor we're using
+
+function initDialogObject()
+{
+  // Create gReplaceDialog object and initialize.
+  gReplaceDialog = {};
+  gReplaceDialog.findInput       = document.getElementById("dialog.findInput");
+  gReplaceDialog.replaceInput    = document.getElementById("dialog.replaceInput");
+  gReplaceDialog.caseSensitive   = document.getElementById("dialog.caseSensitive");
+  gReplaceDialog.wrap            = document.getElementById("dialog.wrap");
+  gReplaceDialog.searchBackwards = document.getElementById("dialog.searchBackwards");
+  gReplaceDialog.findNext        = document.getElementById("findNext");
+  gReplaceDialog.replace         = document.getElementById("replace");
+  gReplaceDialog.replaceAndFind  = document.getElementById("replaceAndFind");
+  gReplaceDialog.replaceAll      = document.getElementById("replaceAll");
+}
+
+function loadDialog()
+{
+  // Set initial dialog field contents.
+  // Set initial dialog field contents. Use the gFindInst attributes first,
+  // this is necessary for window.find()
+  gReplaceDialog.findInput.value         = (gFindInst.searchString
+                                            ? gFindInst.searchString
+                                            : gFindService.searchString);
+  gReplaceDialog.replaceInput.value = gFindService.replaceString;
+  gReplaceDialog.caseSensitive.checked   = (gFindInst.matchCase
+                                            ? gFindInst.matchCase
+                                            : gFindService.matchCase);
+  gReplaceDialog.wrap.checked            = (gFindInst.wrapFind
+                                            ? gFindInst.wrapFind
+                                            : gFindService.wrapFind);
+  gReplaceDialog.searchBackwards.checked = (gFindInst.findBackwards
+                                            ? gFindInst.findBackwards
+                                            : gFindService.findBackwards);
+
+  doEnabling();
+}
+
+function onLoad()
+{
+  // Get the xul <editor> element:
+  var editorElement = window.arguments[0];
+
+  // If we don't get the editor, then we won't allow replacing.
+  gEditor = editorElement.getEditor(editorElement.contentWindow);
+  if (!gEditor)
+  {
+    window.close();
+    return;
+  }
+
+  // Get the nsIWebBrowserFind service:
+  gFindInst = editorElement.webBrowserFind;
+
+  try {
+  // get the find service, which stores global find state
+    gFindService = Components.classes["@mozilla.org/find/find_service;1"]
+                         .getService(Components.interfaces.nsIFindService);
+  } catch(e) { dump("No find service!\n"); gFindService = 0; }
+
+  // Init gReplaceDialog.
+  initDialogObject();
+
+  // Change "OK" to "Find".
+  //dialog.find.label = document.getElementById("fBLT").getAttribute("label");
+
+  // Fill dialog.
+  loadDialog();
+
+  if (gReplaceDialog.findInput.value)
+    gReplaceDialog.findInput.select();
+  else
+    gReplaceDialog.findInput.focus();
+}
+
+function onUnload() {
+  // Disconnect context from this dialog.
+  gFindReplaceData.replaceDialog = null;
+}
+
+function saveFindData()
+{
+  // Set data attributes per user input.
+  if (gFindService)
+  {
+    gFindService.searchString  = gReplaceDialog.findInput.value;
+    gFindService.matchCase     = gReplaceDialog.caseSensitive.checked;
+    gFindService.wrapFind      = gReplaceDialog.wrap.checked;
+    gFindService.findBackwards = gReplaceDialog.searchBackwards.checked;
+  }
+}
+
+function setUpFindInst()
+{
+  gFindInst.searchString  = gReplaceDialog.findInput.value;
+  gFindInst.matchCase     = gReplaceDialog.caseSensitive.checked;
+  gFindInst.wrapFind      = gReplaceDialog.wrap.checked;
+  gFindInst.findBackwards = gReplaceDialog.searchBackwards.checked;
+}
+
+function onFindNext()
+{
+  // Transfer dialog contents to the find service.
+  saveFindData();
+  // set up the find instance
+  setUpFindInst();
+
+  // Search.
+  var result = gFindInst.findNext();
+
+  if (!result)
+  {
+    var bundle = document.getElementById("findBundle");
+    AlertWithTitle(null, bundle.getString("notFoundWarning"));
+    SetTextboxFocus(gReplaceDialog.findInput);
+    gReplaceDialog.findInput.select();
+    gReplaceDialog.findInput.focus();
+    return false;
+  } 
+  return true;
+}
+
+function onReplace()
+{
+  if (!gEditor)
+    return false;
+
+  // Does the current selection match the find string?
+  var selection = gEditor.selection;
+
+  var selStr = selection.toString();
+  var specStr = gReplaceDialog.findInput.value;
+  if (!gReplaceDialog.caseSensitive.checked)
+  {
+    selStr = selStr.toLowerCase();
+    specStr = specStr.toLowerCase();
+  }
+  // Unfortunately, because of whitespace we can't just check
+  // whether (selStr == specStr), but have to loop ourselves.
+  // N chars of whitespace in specStr can match any M >= N in selStr.
+  var matches = true;
+  var specLen = specStr.length;
+  var selLen = selStr.length;
+  if (selLen < specLen)
+    matches = false;
+  else
+  {
+    var specArray = specStr.match(/\S+|\s+/g);
+    var selArray = selStr.match(/\S+|\s+/g);
+    if ( specArray.length != selArray.length)
+      matches = false;
+    else
+    {
+      for (var i=0; i<selArray.length; i++)
+      {
+        if (selArray[i] != specArray[i])
+        {
+          if ( /\S/.test(selArray[i][0]) || /\S/.test(specArray[i][0]) )
+          {
+            // not a space chunk -- match fails
+            matches = false;
+            break;
+          }
+          else if ( selArray[i].length < specArray[i].length )
+          {
+            // if it's a space chunk then we only care that sel be
+            // at least as long as spec
+            matches = false;
+            break;
+          }
+        }
+      }
+    }
+  }
+
+  // If the current selection doesn't match the pattern,
+  // then we want to find the next match, but not do the replace.
+  // That's what most other apps seem to do.
+  // So here, just return.
+  if (!matches)
+    return false;
+
+  // Transfer dialog contents to the find service.
+  saveFindData();
+
+  // For reverse finds, need to remember the caret position
+  // before current selection
+  var newRange;
+  if (gReplaceDialog.searchBackwards.checked && selection.rangeCount > 0)
+  {
+    newRange = selection.getRangeAt(0).cloneRange();
+    newRange.collapse(true);
+  }
+
+  // nsPlaintextEditor::InsertText fails if the string is empty,
+  // so make that a special case:
+  var replStr = gReplaceDialog.replaceInput.value;
+  if (replStr == "")
+    gEditor.deleteSelection(0);
+  else
+    gEditor.insertText(replStr);
+
+  // For reverse finds, need to move caret just before the replaced text
+  if (gReplaceDialog.searchBackwards.checked && newRange)
+  {
+    gEditor.selection.removeAllRanges();
+    gEditor.selection.addRange(newRange);
+  }
+
+  return true;
+}
+
+function onReplaceAll()
+{
+  if (!gEditor)
+    return;
+
+  var findStr = gReplaceDialog.findInput.value;
+  var repStr = gReplaceDialog.replaceInput.value;
+
+  // Transfer dialog contents to the find service.
+  saveFindData();
+
+  var finder = Components.classes["@mozilla.org/embedcomp/rangefind;1"].createInstance().QueryInterface(Components.interfaces.nsIFind);
+
+  finder.caseSensitive = gReplaceDialog.caseSensitive.checked;
+  finder.findBackwards = gReplaceDialog.searchBackwards.checked;
+
+  // We want the whole operation to be undoable in one swell foop,
+  // so start a transaction:
+  gEditor.beginTransaction();
+
+  // and to make sure we close the transaction, guard against exceptions:
+  try {
+    // Make a range containing the current selection, 
+    // so we don't go past it when we wrap.
+    var selection = gEditor.selection;
+    var selecRange;
+    if (selection.rangeCount > 0)
+      selecRange = selection.getRangeAt(0);
+    var origRange = selecRange.cloneRange();
+
+    // We'll need a range for the whole document:
+    var wholeDocRange = gEditor.document.createRange();
+    var rootNode = gEditor.rootElement.QueryInterface(Components.interfaces.nsIDOMNode);
+    wholeDocRange.selectNodeContents(rootNode);
+
+    // And start and end points:
+    var endPt = gEditor.document.createRange();
+
+    if (gReplaceDialog.searchBackwards.checked)
+    {
+      endPt.setStart(wholeDocRange.startContainer, wholeDocRange.startOffset);
+      endPt.setEnd(wholeDocRange.startContainer, wholeDocRange.startOffset);
+    }
+    else
+    {
+      endPt.setStart(wholeDocRange.endContainer, wholeDocRange.endOffset);
+      endPt.setEnd(wholeDocRange.endContainer, wholeDocRange.endOffset);
+    }
+
+    // Find and replace from here to end (start) of document:
+    var foundRange;
+    var searchRange = wholeDocRange.cloneRange();
+    while ((foundRange = finder.Find(findStr, searchRange,
+                                     selecRange, endPt)) != null)
+    {
+      gEditor.selection.removeAllRanges();
+      gEditor.selection.addRange(foundRange);
+
+      // The editor will leave the caret at the end of the replaced text.
+      // For reverse finds, we need it at the beginning,
+      // so save the next position now.
+      if (gReplaceDialog.searchBackwards.checked)
+      {
+        selecRange = foundRange.cloneRange();
+        selecRange.setEnd(selecRange.startContainer, selecRange.startOffset);
+      }
+
+      // nsPlaintextEditor::InsertText fails if the string is empty,
+      // so make that a special case:
+      if (repStr == "")
+        gEditor.deleteSelection(0);
+      else
+        gEditor.insertText(repStr);
+
+      // If we're going forward, we didn't save selecRange before, so do it now:
+      if (!gReplaceDialog.searchBackwards.checked)
+      {
+        selection = gEditor.selection;
+        if (selection.rangeCount <= 0) {
+          gEditor.endTransaction();
+          return;
+        }
+        selecRange = selection.getRangeAt(0).cloneRange();
+      }
+    }
+
+    // If no wrapping, then we're done
+    if (!gReplaceDialog.wrap.checked) {
+      gEditor.endTransaction();
+      return;
+    }
+
+    // If wrapping, find from start/end of document back to start point.
+    if (gReplaceDialog.searchBackwards.checked)
+    {
+      // Collapse origRange to end
+      origRange.setStart(origRange.endContainer, origRange.endOffset);
+      // Set current position to document end
+      selecRange.setEnd(wholeDocRange.endContainer, wholeDocRange.endOffset);
+      selecRange.setStart(wholeDocRange.endContainer, wholeDocRange.endOffset);
+    }
+    else
+    {
+      // Collapse origRange to start
+      origRange.setEnd(origRange.startContainer, origRange.startOffset);
+      // Set current position to document start
+      selecRange.setStart(wholeDocRange.startContainer,
+                          wholeDocRange.startOffset);
+      selecRange.setEnd(wholeDocRange.startContainer, wholeDocRange.startOffset);
+    }
+
+    while ((foundRange = finder.Find(findStr, wholeDocRange,
+                                     selecRange, origRange)) != null)
+    {
+      gEditor.selection.removeAllRanges();
+      gEditor.selection.addRange(foundRange);
+
+      // Save insert point for backward case
+      if (gReplaceDialog.searchBackwards.checked)
+      {
+        selecRange = foundRange.cloneRange();
+        selecRange.setEnd(selecRange.startContainer, selecRange.startOffset);
+      }
+
+      // nsPlaintextEditor::InsertText fails if the string is empty,
+      // so make that a special case:
+      if (repStr == "")
+        gEditor.deleteSelection(0);
+      else
+        gEditor.insertText(repStr);
+
+      // Get insert point for forward case
+      if (!gReplaceDialog.searchBackwards.checked)
+      {
+        selection = gEditor.selection;
+        if (selection.rangeCount <= 0) {
+          gEditor.endTransaction();
+          return;
+        }
+        selecRange = selection.getRangeAt(0);
+      }
+    }
+  } // end try
+  catch (e) { }
+
+  gEditor.endTransaction();
+}
+
+function doEnabling()
+{
+  var findStr = gReplaceDialog.findInput.value;
+  var repStr = gReplaceDialog.replaceInput.value;
+  gReplaceDialog.enabled = findStr;
+  gReplaceDialog.findNext.disabled = !findStr;
+  gReplaceDialog.replace.disabled = !findStr;
+  gReplaceDialog.replaceAndFind.disabled = !findStr;
+  gReplaceDialog.replaceAll.disabled = !findStr;
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdReplace.xul
@@ -0,0 +1,101 @@
+<?xml version="1.0"?>
+
+<!-- ***** BEGIN LICENSE BLOCK *****
+ Version: MPL 1.1/GPL 2.0/LGPL 2.1
+
+ The contents of this file are subject to the Mozilla Public License Version
+ 1.1 (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ for the specific language governing rights and limitations under the
+ License.
+
+ The Original Code is Mozilla Communicator client code, released
+ March 31, 1998.
+
+ The Initial Developer of the Original Code is
+ Netscape Communications Corporation.
+ Portions created by the Initial Developer are Copyright (C) 1998-1999
+ the Initial Developer. All Rights Reserved.
+
+ Contributor(s):
+   Kin Blas <kin@netscape.com>
+   Akkana Peck <akkana@netscape.com>
+
+ Alternatively, the contents of this file may be used under the terms of
+ either of the GNU General Public License Version 2 or later (the "GPL"),
+ or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ in which case the provisions of the GPL or the LGPL are applicable instead
+ of those above. If you wish to allow use of your version of this file only
+ under the terms of either the GPL or the LGPL, and not to allow others to
+ use your version of this file under the terms of the MPL, indicate your
+ decision by deleting the provisions above and replace them with the notice
+ and other provisions required by the GPL or the LGPL. If you do not delete
+ the provisions above, a recipient may use your version of this file under
+ the terms of any one of the MPL, the GPL or the LGPL.
+
+ ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorReplace.dtd">
+
+<dialog id="replaceDlg" title="&replaceDialog.title;"
+   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+   persist="screenX screenY"
+   buttons="cancel"
+   onload = "onLoad()"
+   ondialogaccept="return onFindNext();">
+
+  <!-- Methods common to all editor dialogs -->
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdReplace.js"/>
+  <stringbundle id="findBundle" src="chrome://global/locale/finddialog.properties"/>
+   
+  <hbox>
+    <vbox>
+      <spacer class="spacer"/>
+      <grid align="start">
+        <columns><column/><column/></columns>
+        <rows>
+          <row align="center">
+            <label value="&findField.label;" accesskey="&findField.accesskey;" control="dialog.findInput"/>
+            <textbox id="dialog.findInput" oninput="doEnabling();"/>
+          </row>
+          <row align="center">
+            <label value="&replaceField.label;" accesskey="&replaceField.accesskey;" control="dialog.replaceInput"/>
+            <textbox id="dialog.replaceInput" oninput="doEnabling();"/>
+          </row>
+          <row align="start">
+            <spacer/>
+            <vbox align="start">
+              <spacer class="bigspacer"/>
+              <checkbox id="dialog.caseSensitive" label="&caseSensitiveCheckbox.label;" 
+                  accesskey="&caseSensitiveCheckbox.accesskey;"/>
+              <checkbox id="dialog.wrap" label="&wrapCheckbox.label;" 
+                  accesskey="&wrapCheckbox.accesskey;"/>
+              <checkbox id="dialog.searchBackwards" label="&backwardsCheckbox.label;" 
+                  accesskey="&backwardsCheckbox.accesskey;"/>
+            </vbox>
+          </row>
+        </rows>
+      </grid>
+    </vbox>
+    <vbox>
+      <button id="findNext" label="&findNextButton.label;" accesskey="&findNextButton.accesskey;" 
+          oncommand="onFindNext();" default="true"/>
+      <button id="replace" label="&replaceButton.label;" accesskey="&replaceButton.accesskey;" 
+          oncommand="onReplace();"/>
+      <button id="replaceAndFind" label="&replaceAndFindButton.label;" 
+          accesskey="&replaceAndFindButton.accesskey;" oncommand="onReplace(); onFindNext();"/>
+      <button id="replaceAll" label="&replaceAllButton.label;" 
+          accesskey="&replaceAllButton.accesskey;" oncommand="onReplaceAll();"/>
+      <button dlgtype="cancel" label="&closeButton.label;"/>
+    </vbox>
+  </hbox>
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdSelectProps.js
@@ -0,0 +1,790 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Selection List Properties Dialog.
+ *
+ * The Initial Developer of the Original Code is
+ * Neil Rashbrook.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s): Neil Rashbrook <neil@parkwaycc.co.uk>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// Global variables
+
+var atomService = Components.classes["@mozilla.org/atom-service;1"]
+                            .getService(Components.interfaces.nsIAtomService);
+var checkedAtoms = {
+  "false":  atomService.getAtom("checked-false"),
+  "true":   atomService.getAtom("checked-true")};
+
+var hasValue;
+var oldValue;
+var insertNew;
+var itemArray;
+var treeBoxObject;
+var treeSelection;
+var selectElement;
+var currentItem = null;
+var selectedOption = null;
+var selectedOptionCount = 0;
+
+// Utility functions
+
+function getParentIndex(index)
+{
+  switch (itemArray[index].level)
+  {
+  case 0: return -1;
+  case 1: return 0;
+  }
+  while (itemArray[--index].level > 1);
+  return index;
+}
+
+function UpdateSelectMultiple()
+{
+  if (selectedOptionCount > 1)
+  {
+    gDialog.selectMultiple.checked = true;
+    gDialog.selectMultiple.disabled = true;
+  }
+  else
+    gDialog.selectMultiple.disabled = false;
+}
+
+/* wrapper objects:
+ * readonly attribute Node element; // DOM node (select/optgroup/option)
+ * readonly attribute int level; // tree depth
+ * readonly attribute boolean container; // can contain options
+ * string getCellText(string col); // tree view helper
+ * string cycleCell(int currentIndex); // tree view helper
+ * void onFocus(); // load data into deck
+ * void onBlur(); // save data from deck
+ * boolean canDestroy(boolean prompt); // NB prompt not used
+ * void destroy(); // post remove callback
+ * void moveUp();
+ * boolean canMoveDown();
+ * void moveDown();
+ * void appendOption(newElement, currentIndex);
+ */
+
+// OPTION element wrapper object
+
+// Create a wrapper for the given element at the given level
+function optionObject(option, level)
+{
+  // select an added option (when loading from document)
+  if (option.hasAttribute("selected"))
+    selectedOptionCount++;
+  this.level = level;
+  this.element = option;
+}
+
+optionObject.prototype.container = false;
+
+optionObject.prototype.getCellText = function getCellText(column)
+{
+  if (column.id == "SelectSelCol")
+    return "";
+  if (column.id == "SelectValCol" && this.element.hasAttribute("value"))
+    return this.element.getAttribute("value");
+  return this.element.text;
+}
+
+optionObject.prototype.cycleCell = function cycleCell(index)
+{
+  if (this.element.hasAttribute("selected"))
+  {
+    this.element.removeAttribute("selected");
+    selectedOptionCount--;
+    selectedOption = null;
+  }
+  else
+  {
+    // Different handling for multiselect lists
+    if (gDialog.selectMultiple.checked || !selectedOption)
+      selectedOptionCount++;
+    else if (selectedOption)
+    {
+      selectedOption.removeAttribute("selected");
+      var column = treeBoxObject.columns["SelectSelCol"];
+      treeBoxObject.invalidateColumn(column);
+      selectedOption = null;
+    }
+    this.element.setAttribute("selected", "");
+    selectedOption = this.element;
+    var column = treeBoxObject.columns["SelectSelCol"];
+    treeBoxObject.invalidateCell(index, column);
+  }
+  if (currentItem == this)
+    // Also update the deck
+    gDialog.optionSelected.setAttribute("checked", this.element.hasAttribute("selected"));
+  UpdateSelectMultiple();
+};
+
+optionObject.prototype.onFocus = function onFocus()
+{
+  gDialog.optionText.value = this.element.text;
+  hasValue = this.element.hasAttribute("value");
+  oldValue = this.element.value;
+  gDialog.optionHasValue.checked = hasValue;
+  gDialog.optionValue.value = hasValue ? this.element.value : this.element.text;
+  gDialog.optionSelected.checked = this.element.hasAttribute("selected");
+  gDialog.optionDisabled.checked = this.element.hasAttribute("disabled");
+  gDialog.selectDeck.setAttribute("selectedIndex", "2");
+};
+
+optionObject.prototype.onBlur = function onBlur()
+{
+  this.element.text = gDialog.optionText.value;
+  if (gDialog.optionHasValue.checked)
+    this.element.value = gDialog.optionValue.value;
+  else
+    this.element.removeAttribute("value");
+  if (gDialog.optionSelected.checked)
+    this.element.setAttribute("selected", "");
+  else
+    this.element.removeAttribute("selected");
+  if (gDialog.optionDisabled.checked)
+    this.element.setAttribute("disabled", "");
+  else
+    this.element.removeAttribute("disabled");
+};
+
+optionObject.prototype.canDestroy = function canDestroy(prompt)
+{
+  return true;
+/*return !prompt ||
+    ConfirmWithTitle(GetString("DeleteOption"),
+                     GetString("DeleteOptionMsg"),
+                     GetString("DeleteOption"));*/
+};
+
+optionObject.prototype.destroy = function destroy()
+{
+  // Deselect a removed option
+  if (this.element.hasAttribute("selected"))
+  {
+    selectedOptionCount--;
+    selectedOption = null;
+    UpdateSelectMultiple();
+  }
+};
+
+/* 4 cases:
+ * a) optgroup -> optgroup
+ *      ...         ...
+ *    option        option
+ * b) optgroup -> option
+ *      option    optgroup
+ *      ...         ...
+ * c) option
+ *    option
+ * d)   option
+ *      option
+ */
+
+optionObject.prototype.moveUp = function moveUp()
+{
+  var i;
+  var index = treeSelection.currentIndex;
+  if (itemArray[index].level < itemArray[index - 1].level + itemArray[index - 1].container)
+  {
+    // we need to repaint the tree's lines
+    treeBoxObject.invalidateRange(getParentIndex(index), index);
+    // a) option is just after an optgroup, so it becomes the last child
+    itemArray[index].level = 2;
+    treeBoxObject.view.selectionChanged();
+  }
+  else
+  {
+    // otherwise new option level is now the same as the previous item
+    itemArray[index].level = itemArray[index - 1].level;
+    // swap the option with the previous item
+    itemArray.splice(index, 0, itemArray.splice(--index, 1)[0]);
+  }
+  selectTreeIndex(index, true);
+}
+
+optionObject.prototype.canMoveDown = function canMoveDown()
+{
+  // move down is not allowed on the last option if its level is 1
+  return this.level > 1 || itemArray.length - treeSelection.currentIndex > 1;
+}
+
+optionObject.prototype.moveDown = function moveDown()
+{
+  var i;
+  var index = treeSelection.currentIndex;
+  if (index + 1 == itemArray.length || itemArray[index].level > itemArray[index + 1].level)
+  {
+    // we need to repaint the tree's lines
+    treeBoxObject.invalidateRange(getParentIndex(index), index);
+    // a) option is last child of an optgroup, so it moves just after
+    itemArray[index].level = 1;
+    treeBoxObject.view.selectionChanged();
+  }
+  else
+  {
+    // level increases if the option was preceding an optgroup
+    itemArray[index].level += itemArray[index + 1].container;
+    // swap the option with the next item
+    itemArray.splice(index, 0, itemArray.splice(++index, 1)[0]);
+  }
+  selectTreeIndex(index, true);
+}
+
+optionObject.prototype.appendOption = function appendOption(child, parent)
+{
+  // special case quick check
+  if (this.level == 1)
+    return gDialog.appendOption(child, 0);
+
+  // append the option to the parent element
+  parent = getParentIndex(parent);
+  return itemArray[parent].appendOption(child, parent);
+};
+
+// OPTGROUP element wrapper object
+
+function optgroupObject(optgroup)
+{
+  this.element = optgroup;
+}
+
+optgroupObject.prototype.level = 1;
+
+optgroupObject.prototype.container = true;
+
+optgroupObject.prototype.getCellText = function getCellText(column)
+{
+  return column.id == "SelectTextCol" ? this.element.label : "";
+}
+
+optgroupObject.prototype.cycleCell = function cycleCell(index)
+{
+};
+
+optgroupObject.prototype.onFocus = function onFocus()
+{
+  gDialog.optgroupLabel.value = this.element.label;
+  gDialog.optgroupDisabled.checked = this.element.disabled;
+  gDialog.selectDeck.setAttribute("selectedIndex", "1");
+};
+
+optgroupObject.prototype.onBlur = function onBlur()
+{
+  this.element.label = gDialog.optgroupLabel.value;
+  this.element.disabled = gDialog.optgroupDisabled.checked;
+};
+
+optgroupObject.prototype.canDestroy = function canDestroy(prompt)
+{
+  // Only removing empty option groups for now
+  return gDialog.nextChild(treeSelection.currentIndex) - treeSelection.currentIndex == 1;
+/*&& (!prompt ||
+    ConfirmWithTitle(GetString("DeleteOptGroup"),
+                     GetString("DeleteOptGroupMsg"),
+                     GetString("DeleteOptGroup")));
+*/
+};
+
+optgroupObject.prototype.destroy = function destroy()
+{
+};
+
+optgroupObject.prototype.moveUp = function moveUp()
+{
+  // Find the index of the previous and next elements at the same level
+  var index = treeSelection.currentIndex;
+  var i = index;
+  while (itemArray[--index].level > 1);
+  var j = gDialog.nextChild(i);
+  // Cut out the element, cut the array in two, then join together
+  var movedItems = itemArray.splice(i, j - i);
+  var endItems = itemArray.splice(index);
+  itemArray = itemArray.concat(movedItems).concat(endItems);
+  // Repaint the lot
+  treeBoxObject.invalidateRange(index, j);
+  selectTreeIndex(index, true);
+}
+
+optgroupObject.prototype.canMoveDown = function canMoveDown()
+{
+  return gDialog.lastChild() > treeSelection.currentIndex;
+}
+
+optgroupObject.prototype.moveDown = function moveDown()
+{
+  // Find the index of the next two elements at the same level
+  var index = treeSelection.currentIndex;
+  var i = gDialog.nextChild(index);
+  var j = gDialog.nextChild(i);
+  // Cut out the element, cut the array in two, then join together
+  var movedItems = itemArray.splice(i, j - 1);
+  var endItems = itemArray.splice(index);
+  itemArray = itemArray.concat(movedItems).concat(endItems);
+  // Repaint the lot
+  treeBoxObject.invalidateRange(index, j);
+  index += j - i;
+  selectTreeIndex(index, true);
+}
+
+optgroupObject.prototype.appendOption = function appendOption(child, parent)
+{
+  var index = gDialog.nextChild(parent);
+  // XXX need to repaint the lines, tree won't do this
+  var primaryCol = treeBoxObject.getPrimaryColumn();
+  treeBoxObject.invalidateCell(index - 1, primaryCol);
+  // insert the wrapped object as the last child
+  itemArray.splice(index, 0, new optionObject(child, 2));
+  treeBoxObject.rowCountChanged(index, 1);
+  selectTreeIndex(index, false);
+};
+
+// dialog initialization code
+
+function Startup()
+{
+  var editor = GetCurrentEditor();
+  if (!editor)
+  {
+    dump("Failed to get active editor!\n");
+    window.close();
+    return;
+  }
+
+  // Get a single selected select element
+  const kTagName = "select";
+  try {
+    selectElement = editor.getSelectedElement(kTagName);
+  } catch (e) {}
+
+  if (selectElement)
+    // We found an element and don't need to insert one
+    insertNew = false;
+  else
+  {
+    insertNew = true;
+
+    // We don't have an element selected,
+    //  so create one with default attributes
+    try {
+      selectElement = editor.createElementWithDefaults(kTagName);
+    } catch (e) {}
+
+    if(!selectElement)
+    {
+      dump("Failed to get selected element or create a new one!\n");
+      window.close();
+      return;
+    }
+  }
+
+  // SELECT element wrapper object
+  gDialog = {
+    // useful elements
+    accept:           document.documentElement.getButton("accept"),
+    selectDeck:       document.getElementById("SelectDeck"),
+    selectName:       document.getElementById("SelectName"),
+    selectSize:       document.getElementById("SelectSize"),
+    selectMultiple:   document.getElementById("SelectMultiple"),
+    selectDisabled:   document.getElementById("SelectDisabled"),
+    selectTabIndex:   document.getElementById("SelectTabIndex"),
+    optgroupLabel:    document.getElementById("OptGroupLabel"),
+    optgroupDisabled: document.getElementById("OptGroupDisabled"),
+    optionText:       document.getElementById("OptionText"),
+    optionHasValue:   document.getElementById("OptionHasValue"),
+    optionValue:      document.getElementById("OptionValue"),
+    optionSelected:   document.getElementById("OptionSelected"),
+    optionDisabled:   document.getElementById("OptionDisabled"),
+    removeButton:     document.getElementById("RemoveButton"),
+    previousButton:   document.getElementById("PreviousButton"),
+    nextButton:       document.getElementById("NextButton"),
+    tree:             document.getElementById("SelectTree"),
+    // wrapper methods (except MoveUp and MoveDown)
+    element:          selectElement.cloneNode(false),
+    level:            0,
+    container:        true,
+    getCellText:      function getCellText(column)
+    {
+      return column.id == "SelectTextCol" ? this.element.getAttribute("name") : "";
+    },
+    cycleCell:        function cycleCell(index) {},
+    onFocus:          function onFocus()
+    {
+      gDialog.selectName.value = this.element.getAttribute("name");
+      gDialog.selectSize.value = this.element.getAttribute("size");
+      gDialog.selectMultiple.checked = this.element.hasAttribute("multiple");
+      gDialog.selectDisabled.checked = this.element.hasAttribute("disabled");
+      gDialog.selectTabIndex.value = this.element.getAttribute("tabindex");
+      this.selectDeck.setAttribute("selectedIndex", "0");
+      onNameInput();
+    },
+    onBlur:           function onBlur()
+    {
+      this.element.setAttribute("name", gDialog.selectName.value);
+      if (gDialog.selectSize.value)
+        this.element.setAttribute("size", gDialog.selectSize.value);
+      else
+        this.element.removeAttribute("size");
+      if (gDialog.selectMultiple.checked)
+        this.element.setAttribute("multiple", "");
+      else
+        this.element.removeAttribute("multiple");
+      if (gDialog.selectDisabled.checked)
+        this.element.setAttribute("disabled", "");
+      else
+        this.element.removeAttribute("disabled");
+      if (gDialog.selectTabIndex.value)
+        this.element.setAttribute("tabindex", gDialog.selectTabIndex.value);
+      else
+        this.element.removeAttribute("tabindex");
+    },
+    appendOption:     function appendOption(child, parent)
+    {
+      var index = itemArray.length;
+      // XXX need to repaint the lines, tree won't do this
+      treeBoxObject.invalidateRange(this.lastChild(), index);
+      // append the wrapped object
+      itemArray.push(new optionObject(child, 1));
+      treeBoxObject.rowCountChanged(index, 1);
+      selectTreeIndex(index, false);
+    },
+    canDestroy:       function canDestroy(prompt)
+    {
+      return false;
+    },
+    canMoveDown:      function canMoveDown()
+    {
+      return false;
+    },
+    // helper methods
+    // Find the index of the next immediate child of the select
+    nextChild:        function nextChild(index)
+    {
+      while (++index < itemArray.length && itemArray[index].level > 1);
+      return index;
+    },
+    // Find the index of the last immediate child of the select
+    lastChild:        function lastChild()
+    {
+      var index = itemArray.length;
+      while (itemArray[--index].level > 1);
+      return index;
+    }
+  }
+  // Start with the <select> wrapper
+  itemArray = [gDialog];
+
+  // We modify the actual option and optgroup elements so clone them first
+  for (var child = selectElement.firstChild; child; child = child.nextSibling)
+  {
+    if (child.tagName == "OPTION")
+      itemArray.push(new optionObject(child.cloneNode(true), 1));
+    else if (child.tagName == "OPTGROUP")
+    {
+      itemArray.push(new optgroupObject(child.cloneNode(false)));
+      for (var grandchild = child.firstChild; grandchild; grandchild = grandchild.nextSibling)
+        if (grandchild.tagName == "OPTION")
+          itemArray.push(new optionObject(grandchild.cloneNode(true), 2));
+    }
+  }
+
+  UpdateSelectMultiple();
+
+  // Define a custom view for the tree
+  treeBoxObject = gDialog.tree.treeBoxObject;
+  treeBoxObject.view = {
+    QueryInterface : function QueryInterface(aIID)
+    {
+      if (aIID.equals(Components.interfaces.nsITreeView) ||
+          aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
+          aIID.equals(Components.interfaces.nsISupports))
+        return this;
+
+      Components.returnCode = Components.results.NS_ERROR_NO_INTERFACE;
+      return null;
+    },
+    // useful for debugging
+    get wrappedJSObject() { return this; },
+    get rowCount() { return itemArray.length; },
+    get selection() { return treeSelection; },
+    set selection(selection) { return treeSelection = selection; },
+    getRowProperties: function getRowProperties(index, column, prop) { },
+    // could have used a wrapper for this
+    getCellProperties: function getCellProperties(index, column, prop)
+    {
+      if (column.id == "SelectSelCol" && !itemArray[index].container)
+        prop.AppendElement(checkedAtoms[itemArray[index].element.hasAttribute("selected")]);
+    },
+    getColumnProperties: function getColumnProperties(column, prop) { },
+    // get info from wrapper
+    isContainer: function isContainer(index) { return itemArray[index].container; },
+    isContainerOpen: function isContainerOpen(index) { return true; },
+    isContainerEmpty: function isContainerEmpty(index) { return true; },
+    isSeparator: function isSeparator(index) { return false; },
+    isSorted: function isSorted() { return false; },
+    // d&d not implemented yet!
+    canDrop: function canDrop(index, orientation) { return false; },
+    drop: function drop(index, orientation) { alert('drop:' + index + ',' + orientation); },
+    // same as the global helper
+    getParentIndex: getParentIndex,
+    // tree needs to know when to paint lines
+    hasNextSibling: function hasNextSibling(index, after)
+    {
+      if (!index)
+        return false;
+      var level = itemArray[index].level;
+      while (++after < itemArray.length)
+        switch (level - itemArray[after].level)
+        {
+        case 1: return false;
+        case 0: return true;
+        }
+      return false;
+    },
+    getLevel: function getLevel(index) { return itemArray[index].level; },
+    getImageSrc: function getImageSrc(index, column) { },
+    getProgressMode : function getProgressMode(index,column) { },
+    getCellValue: function getCellValue(index, column) { },
+    getCellText: function getCellText(index, column) { return itemArray[index].getCellText(column); },
+    setTree: function setTree(tree) { this.tree = tree; },
+    toggleOpenState: function toggleOpenState(index) { },
+    cycleHeader: function cycleHeader(col) { },
+    selectionChanged: function selectionChanged()
+    {
+      // Save current values and update buttons and deck
+      if (currentItem)
+        currentItem.onBlur();
+      var currentIndex = treeSelection.currentIndex;
+      currentItem = itemArray[currentIndex];
+      gDialog.removeButton.disabled = !currentItem.canDestroy();
+      gDialog.previousButton.disabled = currentIndex < 2;
+      gDialog.nextButton.disabled = !currentItem.canMoveDown();
+      // For Advanced Edit
+      globalElement = currentItem.element;
+      currentItem.onFocus();
+    },
+    cycleCell: function cycleCell(index, column) { itemArray[index].cycleCell(index); },
+    isEditable: function isEditable(index, column) { return false; },
+    isSelectable: function isSelectable(index, column) { return false; },
+    performAction: function performAction(action) { },
+    performActionOnCell: function performActionOnCell(action, index, column) { }
+  };
+  treeSelection.select(0);
+  currentItem = gDialog;
+  //onNameInput();
+
+  SetTextboxFocus(gDialog.selectName);
+
+  SetWindowLocation();
+}
+
+// Called from Advanced Edit
+function InitDialog()
+{
+  currentItem.onFocus();
+}
+
+// Called from Advanced Edit
+function ValidateData()
+{
+  currentItem.onBlur();
+  return true;
+}
+
+function onAccept()
+{
+  // All values are valid - copy to actual element in doc or
+  //   element created to insert
+  ValidateData();
+
+  var editor = GetCurrentEditor();
+
+  // Coalesce into one undo transaction
+  editor.beginTransaction();
+
+  try
+  {
+    editor.cloneAttributes(selectElement, gDialog.element);
+
+    if (insertNew)
+      // 'true' means delete the selection before inserting
+      editor.insertElementAtSelection(selectElement, true);
+
+    editor.setShouldTxnSetSelection(false);
+
+    while (selectElement.lastChild)
+      editor.deleteNode(selectElement.lastChild);
+
+    var offset = 0;
+    for (var i = 1; i < itemArray.length; i++)
+      if (itemArray[i].level > 1)
+        selectElement.lastChild.appendChild(itemArray[i].element);
+      else
+        editor.insertNode(itemArray[i].element, selectElement, offset++, true);
+
+    editor.setShouldTxnSetSelection(true);
+  }
+  finally
+  {
+    editor.endTransaction();
+  }
+
+  SaveWindowLocation();
+
+  return true;
+}
+
+// Button actions
+function AddOption()
+{
+  currentItem.appendOption(GetCurrentEditor().createElementWithDefaults("option"), treeSelection.currentIndex);
+  SetTextboxFocus(gDialog.optionText);
+}
+
+function AddOptGroup()
+{
+  var optgroupElement = GetCurrentEditor().createElementWithDefaults("optgroup");
+  var index = itemArray.length;
+  // XXX need to repaint the lines, tree won't do this
+  treeBoxObject.invalidateRange(gDialog.lastChild(), index);
+  // append the wrapped object
+  itemArray.push(new optgroupObject(optgroupElement));
+  treeBoxObject.rowCountChanged(index, 1);
+  selectTreeIndex(index, false);
+  SetTextboxFocus(gDialog.optgroupLabel);
+}
+
+function RemoveElement()
+{
+  if (currentItem.canDestroy(true))
+  {
+    // Only removing empty option groups for now
+    var index = treeSelection.currentIndex;
+    var level = itemArray[index].level;
+    // Perform necessary cleanup and remove the wrapper
+    itemArray[index].destroy();
+    itemArray.splice(index, 1);
+    --index;
+    // XXX need to repaint the lines, tree won't do this
+    if (level == 1) {
+      var last = gDialog.lastChild();
+      if (index > last)
+        treeBoxObject.invalidateRange(last, index);
+    }
+    selectTreeIndex(index, true);
+    treeBoxObject.rowCountChanged(++index, -1);
+  }
+}
+
+// Event handler
+function onTreeKeyUp(event)
+{
+  if (event.keyCode == event.DOM_VK_SPACE)
+    currentItem.cycleCell();
+}
+
+function onNameInput()
+{
+  var disabled = !gDialog.selectName.value;
+  if (gDialog.accept.disabled != disabled)
+    gDialog.accept.disabled = disabled;
+  gDialog.element.setAttribute("name", gDialog.selectName.value);
+  // repaint the tree
+  var primaryCol = treeBoxObject.getPrimaryColumn();
+  treeBoxObject.invalidateCell(treeSelection.currentIndex, primaryCol);
+}
+
+function onLabelInput()
+{
+  currentItem.element.setAttribute("label", gDialog.optgroupLabel.value);
+  // repaint the tree
+  var primaryCol = treeBoxObject.getPrimaryColumn();
+  treeBoxObject.invalidateCell(treeSelection.currentIndex, primaryCol);
+}
+
+function onTextInput()
+{
+  currentItem.element.text = gDialog.optionText.value;
+  // repaint the tree
+  if (hasValue) {
+    var primaryCol = treeBoxObject.getPrimaryColumn();
+    treeBoxObject.invalidateCell(treeSelection.currentIndex, primaryCol);
+  }
+  else
+  {
+    gDialog.optionValue.value = gDialog.optionText.value;
+    treeBoxObject.invalidateRow(treeSelection.currentIndex);
+  }
+}
+
+function onValueInput()
+{
+  gDialog.optionHasValue.checked = hasValue = true;
+  oldValue = gDialog.optionValue.value;
+  currentItem.element.setAttribute("value", oldValue);
+  // repaint the tree
+  var column = treeBoxObject.columns["SelectValCol"];
+  treeBoxObject.invalidateCell(treeSelection.currentIndex, column);
+}
+
+function onHasValueClick()
+{
+  hasValue = gDialog.optionHasValue.checked;
+  if (hasValue)
+  {
+    gDialog.optionValue.value = oldValue;
+    currentItem.element.setAttribute("value", oldValue);
+  }
+  else
+  {
+    oldValue = gDialog.optionValue.value;
+    gDialog.optionValue.value = gDialog.optionText.value;
+    currentItem.element.removeAttribute("value");
+  }
+  // repaint the tree
+  var column = treeBoxObject.columns["SelectValCol"];
+  treeBoxObject.invalidateCell(treeSelection.currentIndex, column);
+}
+
+function onSelectMultipleClick()
+{
+  // Recalculate the unique selected option if we need it and have lost it
+  if (!gDialog.selectMultiple.checked && selectedOptionCount == 1 && !selectedOption)
+    for (var i = 1; !(selectedOption = itemArray[i].element).hasAttribute("selected"); i++);
+}
+
+function selectTreeIndex(index, focus)
+{
+  treeSelection.select(index);
+  treeBoxObject.ensureRowIsVisible(index);
+  if (focus)
+    gDialog.tree.focus();
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdSelectProps.xul
@@ -0,0 +1,161 @@
+<?xml version="1.0"?>
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Selection List Properties Dialog.
+   -
+   - The Initial Developer of the Original Code is
+   - Neil Rashbrook.
+   - Portions created by the Initial Developer are Copyright (C) 2001
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s): Neil Rashbrook <neil@parkwaycc.co.uk>
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either the GNU General Public License Version 2 or later (the "GPL"), or
+   - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the LGPL or the GPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?> 
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorSelectProperties.dtd">
+<dialog title="&windowTitle.label;"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        onload="Startup();"
+        buttons="accept,cancel"
+        ondialogaccept="return onAccept();"
+        ondialogcancel="return onCancel();">
+
+  <!-- Methods common to all editor dialogs -->
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdSelectProps.js"/>
+
+  <broadcaster id="args" value=""/>
+  <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+  <!-- Setting rows="7" on tree isn't working, equalsize vbox sets tree height. -->
+  <vbox equalsize="always">
+    <tree id="SelectTree" onselect="treeBoxObject.view.selectionChanged();" onkeyup="onTreeKeyUp(event);">
+      <treecols id="SelectCols">
+        <treecol id="SelectTextCol" flex="3" label="&TextHeader.label;" primary="true"/>
+        <splitter class="tree-splitter"/>
+        <treecol id="SelectValCol" flex="2" label="&ValueHeader.label;"/>
+        <treecol id="SelectSelCol" label="&SelectedHeader.label;" cycler="true"/>
+      </treecols>
+
+      <treechildren id="SelectTreeChildren"/>
+    </tree>
+
+    <hbox flex="1">
+      <deck flex="1" id="SelectDeck" index="0">
+        <groupbox flex="1"><caption label="&Select.label;"/>
+          <grid flex="1"><columns><column flex="1"/><column/></columns>
+            <rows>
+              <row align="center">
+                <label control="SelectName" value="&SelectName.label;" accesskey="&SelectName.accesskey;"/>
+                <textbox id="SelectName" flex="1" oninput="onNameInput();"/>
+              </row>
+              <row align="center">
+                <label control="SelectSize" value="&SelectSize.label;" accesskey="&SelectSize.accesskey;"/>
+                <hbox>
+                  <textbox id="SelectSize" class="narrow" oninput="forceInteger(this.id);"/>
+                </hbox>
+              </row>
+              <row>
+                <spacer/>
+                <checkbox id="SelectMultiple" flex="1" label="&SelectMultiple.label;" accesskey="&SelectMultiple.accesskey;" oncommand="onSelectMultipleClick();"/>
+              </row>
+              <row>
+                <spacer/>
+                <checkbox id="SelectDisabled" flex="1" label="&SelectDisabled.label;" accesskey="&SelectDisabled.accesskey;"/>
+              </row>
+              <row align="center">
+                <label control="SelectTabIndex" value="&SelectTabIndex.label;" accesskey="&SelectTabIndex.accesskey;"/>
+                <hbox>
+                  <textbox id="SelectTabIndex" class="narrow" oninput="forceInteger(this.id);"/>
+                </hbox>
+              </row>
+            </rows>
+          </grid>
+        </groupbox>
+
+        <groupbox flex="1"><caption label="&OptGroup.label;"/>
+          <grid flex="1"><columns><column flex="1"/><column/></columns>
+            <rows>
+              <row align="center">
+                <label control="OptGroupLabel" value="&OptGroupLabel.label;" accesskey="&OptGroupLabel.accesskey;"/>
+                <textbox id="OptGroupLabel" oninput="onLabelInput();"/>
+              </row>
+              <row>
+                <spacer/>
+                <checkbox id="OptGroupDisabled" label="&OptGroupDisabled.label;" accesskey="&OptGroupDisabled.accesskey;"/>
+              </row>
+            </rows>
+          </grid>
+        </groupbox>
+
+        <groupbox flex="1"><caption label="&Option.label;"/>
+          <grid flex="1"><columns><column flex="1"/><column/></columns>
+            <rows>
+              <row align="center">
+                <label control="OptionText" value="&OptionText.label;" accesskey="&OptionText.accesskey;"/>
+                <textbox id="OptionText" oninput="onTextInput();"/>
+              </row>
+              <row align="center">
+                <checkbox id="OptionHasValue" label="&OptionValue.label;" accesskey="&OptionValue.accesskey;" oncommand="onHasValueClick();"/>
+                <textbox id="OptionValue" oninput="onValueInput();"/>
+              </row>
+              <row>
+                <spacer/>
+                <checkbox id="OptionSelected" label="&OptionSelected.label;" accesskey="&OptionSelected.accesskey;" oncommand="currentItem.cycleCell();"/>
+              </row>
+              <row>
+                <spacer/>
+                <checkbox id="OptionDisabled" label="&OptionDisabled.label;" accesskey="&OptionDisabled.accesskey;"/>
+              </row>
+            </rows>
+          </grid>
+        </groupbox>
+      </deck>
+
+      <vbox>
+        <button label="&AddOption.label;" accesskey="&AddOption.accesskey;" oncommand="AddOption();"/>
+        <button label="&AddOptGroup.label;" accesskey="&AddOptGroup.accesskey;" oncommand="AddOptGroup();"/>
+        <button id="RemoveButton" label="&RemoveElement.label;" accesskey="&RemoveElement.accesskey;"
+                oncommand="RemoveElement();" disabled="true"/>
+        <button id="PreviousButton" label="&MoveElementUp.label;" accesskey="&MoveElementUp.accesskey;"
+                oncommand="currentItem.moveUp();" disabled="true" type="row"/>
+        <button id="NextButton" label="&MoveElementDown.label;" accesskey="&MoveElementDown.accesskey;"
+                oncommand="currentItem.moveDown();" disabled="true" type="row"/>
+        <spacer flex="1"/>
+        <button id="AdvancedEditButton"/>
+      </vbox>
+    </hbox>
+  </vbox>
+
+  <separator class="groove"/>
+
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdSnapToGrid.js
@@ -0,0 +1,94 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var gPrefs = GetPrefs();
+var gEditor;
+
+// dialog initialization code
+function Startup()
+{
+  gEditor = GetCurrentEditor();
+  if (!gEditor)
+  {
+    window.close();
+    return;
+  }
+
+  gEditor instanceof Components.interfaces.nsIHTMLAbsPosEditor;
+
+  gDialog.enableSnapToGrid = document.getElementById("enableSnapToGrid");
+  gDialog.sizeInput        = document.getElementById("size");
+  gDialog.sizeLabel        = document.getElementById("sizeLabel");
+  gDialog.unitLabel        = document.getElementById("unitLabel");
+
+  // Initialize control values based on existing attributes
+  InitDialog()
+
+  // SET FOCUS TO FIRST CONTROL
+  SetTextboxFocus(gDialog.sizeInput);
+
+  // Resize window
+  window.sizeToContent();
+
+  SetWindowLocation();
+}
+
+// Set dialog widgets with attribute data
+// We get them from globalElement copy so this can be used
+//   by AdvancedEdit(), which is shared by all property dialogs
+function InitDialog()
+{
+  gDialog.enableSnapToGrid.checked = gEditor.snapToGridEnabled;
+  toggleSnapToGrid();
+
+  gDialog.sizeInput.value = gEditor.gridSize;
+}
+
+function onAccept()
+{
+  gEditor.snapToGridEnabled = gDialog.enableSnapToGrid.checked;
+  gEditor.gridSize = gDialog.sizeInput.value;
+
+  return true;
+}
+
+function toggleSnapToGrid()
+{
+  SetElementEnabledById("size", gDialog.enableSnapToGrid.checked)
+  SetElementEnabledById("sizeLabel", gDialog.enableSnapToGrid.checked)
+  SetElementEnabledById("unitLabel", gDialog.enableSnapToGrid.checked)
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdSnapToGrid.xul
@@ -0,0 +1,87 @@
+<?xml version="1.0"?>
+
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla.org.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 2003
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -   Daniel Glazman (glazman@netscape.com) (Original author)
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either the GNU General Public License Version 2 or later (the "GPL"), or
+   - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the LGPL or the GPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?> 
+<?xul-overlay href="chrome://global/content/globalOverlay.xul"?>
+<?xul-overlay href="chrome://communicator/content/utilityOverlay.xul"?> 
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorSnapToGrid.dtd">
+
+<dialog title="&windowTitle.label;"
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    onload="Startup()"
+    ondialogaccept="return onAccept();"
+    ondialogcancel="return onCancel();">
+
+  <!-- Methods common to all editor dialogs -->
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <!--- Element-specific methods -->
+  <script type="application/x-javascript" src="chrome://editor/content/EdSnapToGrid.js"/>
+
+  <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+  <checkbox id="enableSnapToGrid"
+            label="&enableSnapToGrid.label;"
+            accesskey="&enableSnapToGrid.accessKey;"
+            oncommand="toggleSnapToGrid();"/>
+
+  <spacer class="spacer"/>
+
+  <grid>
+    <columns><column/><column/><column /></columns>
+    <rows>
+      <row align="center">
+        <label value="&sizeEditField.label;"
+               id="sizeLabel"
+               control="size"
+               accesskey="&sizeEditField.accessKey;"/>
+        <textbox class="narrow" id="size" oninput="forceInteger('size')"/>
+        <label id="unitLabel"
+               value="&pixelsLabel.value;" />
+      </row>
+    </rows>
+  </grid>
+
+  <spacer class="spacer"/>
+  <separator class="groove"/>
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdSpellCheck.js
@@ -0,0 +1,621 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Charles Manske (cmanske@netscape.com)
+ *   Neil Rashbrook (neil@parkwaycc.co.uk)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var gMisspelledWord;
+var gSpellChecker = null;
+var gAllowSelectWord = true;
+var gPreviousReplaceWord = "";
+var gFirstTime = true;
+var gLastSelectedLang = null;
+var gDictCount = 0;
+
+function Startup()
+{
+  var sendMailMessageMode = false;
+
+  var editor = GetCurrentEditor();
+  if (!editor)
+  {
+    window.close();
+    return;
+  }
+
+  // Get the spellChecker shell
+  gSpellChecker = Components.classes['@mozilla.org/editor/editorspellchecker;1'].createInstance(Components.interfaces.nsIEditorSpellCheck);
+  if (!gSpellChecker)
+  {
+    dump("SpellChecker not found!!!\n");
+    window.close();
+    return;
+  }
+
+  // Start the spell checker module.
+  try {
+    // TxtSrv Filter Contract Id
+    var filterContractId;
+    sendMailMessageMode = window.arguments[0];
+    var skipBlockQuotes = window.arguments[1];
+    var enableSelectionChecking = window.arguments[2];
+
+    if (skipBlockQuotes)
+      filterContractId = "@mozilla.org/editor/txtsrvfiltermail;1";
+    else
+      filterContractId = "@mozilla.org/editor/txtsrvfilter;1";
+
+    gSpellChecker.setFilter(Components.classes[filterContractId].createInstance(Components.interfaces.nsITextServicesFilter));
+    gSpellChecker.InitSpellChecker(editor, enableSelectionChecking);
+
+  }
+  catch(ex) {
+   dump("*** Exception error: InitSpellChecker\n");
+    window.close();
+    return;
+  }
+
+  gDialog.MisspelledWordLabel = document.getElementById("MisspelledWordLabel");
+  gDialog.MisspelledWord      = document.getElementById("MisspelledWord");
+  gDialog.ReplaceButton       = document.getElementById("Replace");
+  gDialog.IgnoreButton        = document.getElementById("Ignore");
+  gDialog.StopButton          = document.getElementById("Stop");
+  gDialog.CloseButton         = document.getElementById("Close");
+  gDialog.ReplaceWordInput    = document.getElementById("ReplaceWordInput");
+  gDialog.SuggestedList       = document.getElementById("SuggestedList");
+  gDialog.LanguageMenulist    = document.getElementById("LanguageMenulist");
+
+  // Fill in the language menulist and sync it up
+  // with the spellchecker's current language.
+
+  var curLang;
+
+  try {
+    curLang = gSpellChecker.GetCurrentDictionary();
+  } catch(ex) {
+    curLang = "";
+  }
+
+  InitLanguageMenu(curLang);
+  
+  // Get the first misspelled word and setup all UI
+  NextWord();
+
+  // When startup param is true, setup different UI when spell checking 
+  //   just before sending mail message  
+  if (sendMailMessageMode)
+  {
+    // If no misspelled words found, simply close dialog and send message
+    if (!gMisspelledWord)
+    {
+      onClose();
+      return;
+    }
+
+    // Hide "Close" button and use "Send" instead
+    gDialog.CloseButton.hidden = true;
+    gDialog.CloseButton = document.getElementById("Send");
+    gDialog.CloseButton.hidden = false;
+  }
+  else
+  {
+    // Normal spell checking - hide the "Stop" button
+    // (Note that this button is the "Cancel" button for
+    //  Esc keybinding and related window close actions)
+    gDialog.StopButton.hidden = true;
+  }
+
+  // Clear flag that determines message when
+  //  no misspelled word is found
+  //  (different message when used for the first time)
+  gFirstTime = false;
+}
+
+function InitLanguageMenu(aCurLang)
+{
+
+  var o1 = {};
+  var o2 = {};
+
+  // Get the list of dictionaries from
+  // the spellchecker.
+
+  try
+  {
+    gSpellChecker.GetDictionaryList(o1, o2);
+  }
+  catch(ex)
+  {
+    dump("Failed to get DictionaryList!\n");
+    return;
+  }
+
+  var dictList = o1.value;
+  var count    = o2.value;
+
+  // If we're not just starting up and dictionary count
+  // hasn't changed then no need to update the menu.
+  if (gDictCount == count)
+    return;
+
+  // Store current dictionary count.
+  gDictCount = count;
+
+  // Load the string bundles that will help us map
+  // RFC 1766 strings to UI strings.
+
+  // Load the language string bundle.
+  var languageBundle = document.getElementById("languageBundle");
+  var regionBundle = null;
+  // If we have a language string bundle, load the region string bundle.
+  if (languageBundle)
+    regionBundle = document.getElementById("regionBundle");
+  
+  var menuStr2;
+  var isoStrArray;
+  var langId;
+  var langLabel;
+  var i;
+
+  for (i = 0; i < count; i++)
+  {
+    try
+    {
+      langId = dictList[i];
+      isoStrArray = dictList[i].split("-");
+
+      if (languageBundle && isoStrArray[0])
+        langLabel = languageBundle.getString(isoStrArray[0].toLowerCase());
+
+      if (regionBundle && langLabel && isoStrArray.length > 1 && isoStrArray[1])
+      {
+        menuStr2 = regionBundle.getString(isoStrArray[1].toLowerCase());
+        if (menuStr2)
+          langLabel += "/" + menuStr2;
+      }
+
+      if (langLabel && isoStrArray.length > 2 && isoStrArray[2])
+        langLabel += " (" + isoStrArray[2] + ")";
+
+      if (!langLabel)
+        langLabel = langId;
+    }
+    catch (ex)
+    {
+      // getString throws an exception when a key is not found in the
+      // bundle. In that case, just use the original dictList string.
+      langLabel = langId;
+    }
+    dictList[i] = [langLabel, langId];
+  }
+  
+  // sort by locale-aware collation
+  dictList.sort(
+    function compareFn(a, b)
+    {
+      return a[0].localeCompare(b[0]);
+    }
+  );
+
+  // Remove any languages from the list.
+  var languageMenuPopup = gDialog.LanguageMenulist.firstChild;
+  while (languageMenuPopup.firstChild.localName != "menuseparator")
+    languageMenuPopup.removeChild(languageMenuPopup.firstChild);
+
+  var defaultItem = null;
+
+  for (i = 0; i < count; i++)
+  {
+    var item = gDialog.LanguageMenulist.insertItemAt(i, dictList[i][0], dictList[i][1]);
+    if (aCurLang && dictList[i][1] == aCurLang)
+      defaultItem = item;
+  }
+
+  // Now make sure the correct item in the menu list is selected.
+  if (defaultItem)
+  {
+    gDialog.LanguageMenulist.selectedItem = defaultItem;
+    gLastSelectedLang = defaultItem;
+  }
+}
+
+function DoEnabling()
+{
+  if (!gMisspelledWord)
+  {
+    // No more misspelled words
+    gDialog.MisspelledWord.setAttribute("value",GetString( gFirstTime ? "NoMisspelledWord" : "CheckSpellingDone"));
+
+    gDialog.ReplaceButton.removeAttribute("default");
+    gDialog.IgnoreButton.removeAttribute("default");
+
+    gDialog.CloseButton.setAttribute("default","true");
+    // Shouldn't have to do this if "default" is true?
+    gDialog.CloseButton.focus();
+
+    SetElementEnabledById("MisspelledWordLabel", false);
+    SetElementEnabledById("ReplaceWordLabel", false);
+    SetElementEnabledById("ReplaceWordInput", false);
+    SetElementEnabledById("CheckWord", false);
+    SetElementEnabledById("SuggestedListLabel", false);
+    SetElementEnabledById("SuggestedList", false);
+    SetElementEnabledById("Ignore", false);
+    SetElementEnabledById("IgnoreAll", false);
+    SetElementEnabledById("Replace", false);
+    SetElementEnabledById("ReplaceAll", false);
+    SetElementEnabledById("AddToDictionary", false);
+  } else {
+    SetElementEnabledById("MisspelledWordLabel", true);
+    SetElementEnabledById("ReplaceWordLabel", true);
+    SetElementEnabledById("ReplaceWordInput", true);
+    SetElementEnabledById("CheckWord", true);
+    SetElementEnabledById("SuggestedListLabel", true);
+    SetElementEnabledById("SuggestedList", true);
+    SetElementEnabledById("Ignore", true);
+    SetElementEnabledById("IgnoreAll", true);
+    SetElementEnabledById("AddToDictionary", true);
+
+    gDialog.CloseButton.removeAttribute("default");
+    SetReplaceEnable();
+  }
+}
+
+function NextWord()
+{
+  gMisspelledWord = gSpellChecker.GetNextMisspelledWord();
+  SetWidgetsForMisspelledWord();
+}
+
+function SetWidgetsForMisspelledWord()
+{
+  gDialog.MisspelledWord.setAttribute("value", TruncateStringAtWordEnd(gMisspelledWord, 30, true));
+
+
+  // Initial replace word is misspelled word
+  gDialog.ReplaceWordInput.value = gMisspelledWord;
+  gPreviousReplaceWord = gMisspelledWord;
+
+  // This sets gDialog.ReplaceWordInput to first suggested word in list
+  FillSuggestedList(gMisspelledWord);
+
+  DoEnabling();
+
+  if (gMisspelledWord)
+    SetTextboxFocus(gDialog.ReplaceWordInput);
+}
+
+function CheckWord()
+{
+  var word = gDialog.ReplaceWordInput.value;
+  if (word) 
+  {
+    if (gSpellChecker.CheckCurrentWord(word))
+    {
+      FillSuggestedList(word);
+      SetReplaceEnable();
+    } 
+    else 
+    {
+      ClearListbox(gDialog.SuggestedList);
+      var item = gDialog.SuggestedList.appendItem(GetString("CorrectSpelling"), "");
+      if (item) item.setAttribute("disabled", "true");
+      // Suppress being able to select the message text
+      gAllowSelectWord = false;
+    }
+  }
+}
+
+function SelectSuggestedWord()
+{
+  if (gAllowSelectWord)
+  {
+    var selectedItem
+    if (gDialog.SuggestedList.selectedItem)
+    {
+      var selValue = gDialog.SuggestedList.selectedItem.getAttribute("label");
+      gDialog.ReplaceWordInput.value = selValue;
+      gPreviousReplaceWord = selValue;
+    }
+    else
+    {
+      gDialog.ReplaceWordInput.value = gPreviousReplaceWord;
+    }
+    SetReplaceEnable();
+  }
+}
+
+function ChangeReplaceWord()
+{
+  // Calling this triggers SelectSuggestedWord(),
+  //  so temporarily suppress the effect of that
+  var saveAllow = gAllowSelectWord;
+  gAllowSelectWord = false;
+
+  // Select matching word in list
+  var newIndex = -1;
+  var newSelectedItem;
+  var replaceWord = TrimString(gDialog.ReplaceWordInput.value);
+  if (replaceWord)
+  {
+    for (var i = 0; i < gDialog.SuggestedList.getRowCount(); i++)
+    {
+      var item = gDialog.SuggestedList.getItemAtIndex(i);
+      if (item.getAttribute("label") == replaceWord)
+      {
+        newSelectedItem = item;
+        break;
+      }
+    }
+  }
+  gDialog.SuggestedList.selectedItem = newSelectedItem;
+
+  gAllowSelectWord = saveAllow;
+
+  // Remember the new word
+  gPreviousReplaceWord = gDialog.ReplaceWordInput.value;
+
+  SetReplaceEnable();
+}
+
+function Ignore()
+{
+  NextWord();
+}
+
+function IgnoreAll()
+{
+  if (gMisspelledWord) {
+    gSpellChecker.IgnoreWordAllOccurrences(gMisspelledWord);
+  }
+  NextWord();
+}
+
+function Replace(newWord)
+{
+  if (!newWord)
+    return;
+
+  if (gMisspelledWord && gMisspelledWord != newWord)
+  {
+    var editor = GetCurrentEditor();
+    editor.beginTransaction();
+    try {
+      gSpellChecker.ReplaceWord(gMisspelledWord, newWord, false);
+    } catch (e) {}
+    editor.endTransaction();
+  }
+  NextWord();
+}
+
+function ReplaceAll()
+{
+  var newWord = gDialog.ReplaceWordInput.value;
+  if (gMisspelledWord && gMisspelledWord != newWord)
+  {
+    var editor = GetCurrentEditor();
+    editor.beginTransaction();
+    try {
+      gSpellChecker.ReplaceWord(gMisspelledWord, newWord, true);
+    } catch (e) {}
+    editor.endTransaction();
+  }
+  NextWord();
+}
+
+function AddToDictionary()
+{
+  if (gMisspelledWord) {
+    gSpellChecker.AddWordToDictionary(gMisspelledWord);
+  }
+  NextWord();
+}
+
+function EditDictionary()
+{
+  window.openDialog("chrome://editor/content/EdDictionary.xul", "_blank", "chrome,close,titlebar,modal", "", gMisspelledWord);
+}
+
+function SelectLanguage()
+{
+  try {
+    var item = gDialog.LanguageMenulist.selectedItem;
+    if (item.value != "more-cmd") {
+      gSpellChecker.SetCurrentDictionary(item.value);
+      gLastSelectedLang = item;
+    }
+    else {
+      var dictionaryUrl = getDictionaryURL();
+                      
+      var ioService = Components.classes["@mozilla.org/network/io-service;1"]
+                                .getService(Components.interfaces.nsIIOService);
+      uri = ioService.newURI(dictionaryUrl, null, null);
+      var protocolSvc = Components.classes["@mozilla.org/uriloader/external-protocol-service;1"]
+                                  .getService(Components.interfaces.nsIExternalProtocolService);
+      if (protocolSvc.isExposedProtocol(uri.scheme))
+        opener.openDialog(getBrowserURL(), "_blank", "all,dialog=no", dictionaryUrl);
+      else
+        protocolSvc.loadUrl(uri);
+
+      if (gLastSelectedLang)
+        gDialog.LanguageMenulist.selectedItem = gLastSelectedLang;
+    }
+  } catch (ex) {
+    dump(ex);
+  }
+}
+
+function getDictionaryURL()
+{
+  var formatter = Components.classes["@mozilla.org/toolkit/URLFormatterService;1"]
+                  .getService(Components.interfaces.nsIURLFormatter);
+                  
+  return formatter.formatURLPref("spellchecker.dictionaries.download.url");
+}
+
+function Recheck()
+{
+  //TODO: Should we bother to add a "Recheck" method to interface?
+  try {
+    var curLang = gSpellChecker.GetCurrentDictionary();
+    gSpellChecker.UninitSpellChecker();
+    gSpellChecker.InitSpellChecker(GetCurrentEditor(), false);
+    gSpellChecker.SetCurrentDictionary(curLang);
+    gMisspelledWord = gSpellChecker.GetNextMisspelledWord();
+    SetWidgetsForMisspelledWord();
+  } catch(ex) {
+    dump(ex);
+  }
+}
+
+function FillSuggestedList(misspelledWord)
+{
+  var list = gDialog.SuggestedList;
+
+  // Clear the current contents of the list
+  gAllowSelectWord = false;
+  ClearListbox(list);
+  var item;
+
+  if (misspelledWord.length > 0)
+  {
+    // Get suggested words until an empty string is returned
+    var count = 0;
+    var firstWord = 0;
+    do {
+      var word = gSpellChecker.GetSuggestedWord();
+      if (count==0)
+        firstWord = word;
+      if (word.length > 0)
+      {
+        list.appendItem(word, "");
+        count++;
+      }
+    } while (word.length > 0);
+
+    if (count == 0)
+    {
+      // No suggestions - show a message but don't let user select it
+      item = list.appendItem(GetString("NoSuggestedWords"));
+      if (item) item.setAttribute("disabled", "true");
+      gAllowSelectWord = false;
+    } else {
+      gAllowSelectWord = true;
+      // Initialize with first suggested list by selecting it
+      gDialog.SuggestedList.selectedIndex = 0;
+    }
+  } 
+  else
+  {
+    item = list.appendItem("", "");
+    if (item)
+      item.setAttribute("disabled", "true");
+  }
+}
+
+function SetReplaceEnable()
+{
+  // Enable "Change..." buttons only if new word is different than misspelled
+  var newWord = gDialog.ReplaceWordInput.value;
+  var enable = newWord.length > 0 && newWord != gMisspelledWord;
+  SetElementEnabledById("Replace", enable);
+  SetElementEnabledById("ReplaceAll", enable);
+  if (enable)
+  {
+    gDialog.ReplaceButton.setAttribute("default","true");
+    gDialog.IgnoreButton.removeAttribute("default");
+  }
+  else
+  {
+    gDialog.IgnoreButton.setAttribute("default","true");
+    gDialog.ReplaceButton.removeAttribute("default");
+  }
+}
+
+function doDefault()
+{
+  if (gDialog.ReplaceButton.getAttribute("default") == "true")
+    Replace(gDialog.ReplaceWordInput.value);
+  else if (gDialog.IgnoreButton.getAttribute("default") == "true")
+    Ignore();
+  else if (gDialog.CloseButton.getAttribute("default") == "true")
+    onClose();
+
+  return false;
+}
+
+function ExitSpellChecker()
+{
+  if (gSpellChecker)
+  {
+    try
+    {
+      var curLang = gSpellChecker.GetCurrentDictionary();
+      gSpellChecker.UninitSpellChecker();
+      if ("@mozilla.org/spellchecker;1" in Components.classes) {
+        var spellChecker = Components.classes["@mozilla.org/spellchecker/engine;1"]
+                                     .getService(Components.interfaces.mozISpellCheckingEngine);
+        spellChecker.dictionary = curLang;
+      }
+      // now check the document over again with the new dictionary
+      // if we have an inline spellchecker
+      if (("InlineSpellCheckerUI" in window.opener) &&
+          window.opener.InlineSpellCheckerUI.enabled)
+        window.opener.InlineSpellCheckerUI.mInlineSpellChecker.spellCheckRange(null);
+    }
+    finally
+    {
+      gSpellChecker = null;
+    }
+  }
+}
+
+function CancelSpellCheck()
+{
+  ExitSpellChecker();
+
+  // Signal to calling window that we canceled
+  window.opener.cancelSendMessage = true;
+  return true;
+}
+
+function onClose()
+{
+  ExitSpellChecker();
+
+  window.opener.cancelSendMessage = false;
+  window.close();
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdSpellCheck.xul
@@ -0,0 +1,147 @@
+<?xml version="1.0"?>
+
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?> 
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?> 
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorSpellCheck.dtd">
+
+<!-- dialog containing a control requiring initial setup -->
+<dialog buttons="cancel" title="&windowTitle.label;"
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    persist="screenX screenY"
+    onload = "Startup()"
+    ondialogaccept="return doDefault();"
+    ondialogcancel="return CancelSpellCheck();">
+
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <script type="application/x-javascript" src="chrome://communicator/content/utilityOverlay.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdSpellCheck.js"/>
+
+  <broadcaster id="args" value=""/>
+
+  <stringbundle id="languageBundle" src="chrome://global/locale/languageNames.properties"/>
+  <stringbundle id="regionBundle" src="chrome://global/locale/regionNames.properties"/>
+
+  <grid>
+    <columns>
+      <column class="spell-check"/>
+      <column class="spell-check" flex="1"/>
+      <column class="spell-check"/>
+    </columns>
+    <rows>
+      <row align="center">
+        <label id="MisspelledWordLabel" value="&misspelledWord.label;"/>
+        <label class="bold" id="MisspelledWord"/>
+        <button class="spell-check" label="&recheckButton.label;" oncommand="Recheck();"
+                accesskey="&recheckButton.accessKey;"/>
+      </row>
+      <row align="center">
+        <label id="ReplaceWordLabel" value="&wordEditField.label;"
+               control="ReplaceWordInput"
+               accesskey="&wordEditField.accessKey;"/>
+        <textbox id="ReplaceWordInput" oninput="ChangeReplaceWord()" flex="1"/>
+        <button id="CheckWord" oncommand="CheckWord()" label="&checkwordButton.label;"
+                accesskey="&checkwordButton.accessKey;"/>
+      </row>
+    </rows>
+  </grid>
+  <label id="SuggestedListLabel" value="&suggestions.label;"
+         control="SuggestedList"
+         accesskey="&suggestions.accessKey;"/>
+  <grid>
+    <columns><column/><column/></columns>
+    <rows>
+      <row flex="1">
+        <!-- BUG! setting class="MinWidth20em" on tree doesn't work (width=0) -->
+        <listbox  rows="6" id="SuggestedList" onselect="SelectSuggestedWord()"
+                  ondblclick="if (gAllowSelectWord) Replace(event.target.getAttribute('label'));"/>
+        <vbox>
+          <grid flex="1">
+            <columns><column class="spell-check" flex="1"/><column class="spell-check" flex="1"/></columns>
+            <rows>
+              <row>
+                <button id="Replace" label="&replaceButton.label;"
+                        oncommand="Replace(gDialog.ReplaceWordInput.value);"
+                        accesskey="&replaceButton.accessKey;"/>
+                <button id="Ignore"  oncommand="Ignore();" label="&ignoreButton.label;"
+                        accesskey="&ignoreButton.accessKey;"/>
+              </row>
+              <row>
+                <button id="ReplaceAll" oncommand="ReplaceAll();" label="&replaceAllButton.label;"
+                        accesskey="&replaceAllButton.accessKey;"/>
+                <button id="IgnoreAll"  oncommand="IgnoreAll();" label="&ignoreAllButton.label;"
+                        accesskey="&ignoreAllButton.accessKey;"/>
+              </row>
+            </rows> 
+          </grid>
+          <spacer flex="1"/>
+          <label value="&userDictionary.label;"/>
+          <hbox flex="1" align="start">
+            <button class="spell-check" id="AddToDictionary" oncommand="AddToDictionary()" label="&addToUserDictionaryButton.label;"
+                    accesskey="&addToUserDictionaryButton.accessKey;"/>
+            <button class="spell-check" id="EditDictionary"  oncommand="EditDictionary()" label="&editUserDictionaryButton.label;"
+                    accesskey="&editUserDictionaryButton.accessKey;"/>
+          </hbox>
+        </vbox>
+      </row>
+      <label value ="&languagePopup.label;"
+             control="LanguageMenulist"
+             accesskey="&languagePopup.accessKey;"/>
+      <row>
+        <menulist id="LanguageMenulist" oncommand="SelectLanguage()">
+          <menupopup onpopupshowing="InitLanguageMenu(gDialog.LanguageMenulist.selectedItem.value);">
+            <!-- dynamic content populated by JS -->
+            <menuseparator/>
+            <menuitem value="more-cmd" label="&moreDictionaries.label;"/>
+          </menupopup>
+        </menulist>
+        <hbox flex="1">
+          <button class="spell-check" dlgtype="cancel" id="Stop" label="&stopButton.label;" oncommand="CancelSpellCheck();"
+                  accesskey="&stopButton.accessKey;"/>
+          <spacer flex="1"/>
+          <button class="spell-check" id="Close" label="&closeButton.label;" oncommand="onClose();"
+                  accesskey="&closeButton.accessKey;"/>
+          <button class="spell-check" id="Send" label="&sendButton.label;" oncommand="onClose();"
+                  accesskey="&sendButton.accessKey;" hidden="true"/>
+        </hbox>
+      </row>
+    </rows>
+  </grid>
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdTableProps.js
@@ -0,0 +1,1314 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Ben Goodger
+ *   Charles Manske (cmanske@netscape.com)
+ *   Neil Rashbrook (neil@parkwaycc.co.uk)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+//Cancel() is in EdDialogCommon.js
+var gTableElement;
+var gCellElement;
+var gTableCaptionElement;
+var globalCellElement;
+var globalTableElement
+var gValidateTab;
+const defHAlign =   "left";
+const centerStr =   "center";  //Index=1
+const rightStr =    "right";   // 2
+const justifyStr =  "justify"; // 3
+const charStr =     "char";    // 4
+const defVAlign =   "middle";
+const topStr =      "top";
+const bottomStr =   "bottom";
+const bgcolor = "bgcolor";
+var gTableColor;
+var gCellColor;
+
+const cssBackgroundColorStr = "background-color";
+
+var gRowCount = 1;
+var gColCount = 1;
+var gLastRowIndex;
+var gLastColIndex;
+var gNewRowCount;
+var gNewColCount;
+var gCurRowIndex;
+var gCurColIndex;
+var gCurColSpan;
+var gSelectedCellsType = 1;
+const SELECT_CELL = 1;
+const SELECT_ROW = 2;
+const SELECT_COLUMN = 3;
+const RESET_SELECTION = 0;
+var gCellData = { value:null, startRowIndex:0, startColIndex:0, rowSpan:0, colSpan:0,
+                 actualRowSpan:0, actualColSpan:0, isSelected:false
+               };
+var gAdvancedEditUsed;
+var gAlignWasChar = false;
+
+/*
+From C++:
+ 0 TABLESELECTION_TABLE
+ 1 TABLESELECTION_CELL   There are 1 or more cells selected
+                          but complete rows or columns are not selected
+ 2 TABLESELECTION_ROW    All cells are in 1 or more rows
+                          and in each row, all cells selected
+                          Note: This is the value if all rows (thus all cells) are selected
+ 3 TABLESELECTION_COLUMN All cells are in 1 or more columns
+*/
+
+var gSelectedCellCount = 0;
+var gApplyUsed = false;
+var gSelection;
+var gCellDataChanged = false;
+var gCanDelete = false;
+var gPrefs = GetPrefs();
+var gUseCSS = true;
+var gActiveEditor;
+
+// dialog initialization code
+function Startup()
+{
+  gActiveEditor = GetCurrentTableEditor();
+  if (!gActiveEditor)
+  {
+    window.close();
+    return;
+  }
+
+  try {
+    gSelection = gActiveEditor.selection;
+  } catch (e) {}
+  if (!gSelection) return;
+
+  // Get dialog widgets - Table Panel
+  gDialog.TableRowsInput = document.getElementById("TableRowsInput");
+  gDialog.TableColumnsInput = document.getElementById("TableColumnsInput");
+  gDialog.TableWidthInput = document.getElementById("TableWidthInput");
+  gDialog.TableWidthUnits = document.getElementById("TableWidthUnits");
+  gDialog.TableHeightInput = document.getElementById("TableHeightInput");
+  gDialog.TableHeightUnits = document.getElementById("TableHeightUnits");
+  try {
+    if (!gPrefs.getBoolPref("editor.use_css") || (gActiveEditor.flags & 1))
+    {
+      gUseCSS = false;
+      var tableHeightLabel = document.getElementById("TableHeightLabel");
+      tableHeightLabel.parentNode.removeChild(tableHeightLabel);
+      gDialog.TableHeightInput.parentNode.removeChild(gDialog.TableHeightInput);
+      gDialog.TableHeightUnits.parentNode.removeChild(gDialog.TableHeightUnits);
+    }
+  } catch (e) {}
+  gDialog.BorderWidthInput = document.getElementById("BorderWidthInput");
+  gDialog.SpacingInput = document.getElementById("SpacingInput");
+  gDialog.PaddingInput = document.getElementById("PaddingInput");
+  gDialog.TableAlignList = document.getElementById("TableAlignList");
+  gDialog.TableCaptionList = document.getElementById("TableCaptionList");
+  gDialog.TableInheritColor = document.getElementById("TableInheritColor");
+  gDialog.TabBox =  document.getElementById("TabBox");
+
+  // Cell Panel
+  gDialog.SelectionList = document.getElementById("SelectionList");
+  gDialog.PreviousButton = document.getElementById("PreviousButton");
+  gDialog.NextButton = document.getElementById("NextButton");
+  // Currently, we always apply changes and load new attributes when changing selection
+  // (Let's keep this for possible future use)
+  //gDialog.ApplyBeforeMove =  document.getElementById("ApplyBeforeMove");
+  //gDialog.KeepCurrentData = document.getElementById("KeepCurrentData");
+
+  gDialog.CellHeightInput = document.getElementById("CellHeightInput");
+  gDialog.CellHeightUnits = document.getElementById("CellHeightUnits");
+  gDialog.CellWidthInput = document.getElementById("CellWidthInput");
+  gDialog.CellWidthUnits = document.getElementById("CellWidthUnits");
+  gDialog.CellHAlignList = document.getElementById("CellHAlignList");
+  gDialog.CellVAlignList = document.getElementById("CellVAlignList");
+  gDialog.CellInheritColor = document.getElementById("CellInheritColor");
+  gDialog.CellStyleList = document.getElementById("CellStyleList");
+  gDialog.TextWrapList = document.getElementById("TextWrapList");
+
+  // In cell panel, user must tell us which attributes to apply via checkboxes,
+  //  else we would apply values from one cell to ALL in selection
+  //  and that's probably not what they expect!
+  gDialog.CellHeightCheckbox = document.getElementById("CellHeightCheckbox");
+  gDialog.CellWidthCheckbox = document.getElementById("CellWidthCheckbox");
+  gDialog.CellHAlignCheckbox = document.getElementById("CellHAlignCheckbox");
+  gDialog.CellVAlignCheckbox = document.getElementById("CellVAlignCheckbox");
+  gDialog.CellStyleCheckbox = document.getElementById("CellStyleCheckbox");
+  gDialog.TextWrapCheckbox = document.getElementById("TextWrapCheckbox");
+  gDialog.CellColorCheckbox = document.getElementById("CellColorCheckbox");
+  gDialog.TableTab = document.getElementById("TableTab");
+  gDialog.CellTab = document.getElementById("CellTab");
+  gDialog.AdvancedEditCell = document.getElementById("AdvancedEditButton2");
+  // Save "normal" tooltip message for Advanced Edit button
+  gDialog.AdvancedEditCellToolTipText = gDialog.AdvancedEditCell.getAttribute("tooltiptext");
+
+  try {
+    gTableElement = gActiveEditor.getElementOrParentByTagName("table", null);
+  } catch (e) {}
+  if(!gTableElement)
+  {
+    dump("Failed to get table element!\n");
+    window.close();
+    return;
+  }
+  globalTableElement = gTableElement.cloneNode(false);
+
+  var tagNameObj = { value: "" };
+  var countObj = { value : 0 };
+  var tableOrCellElement;
+  try {
+   tableOrCellElement = gActiveEditor.getSelectedOrParentTableElement(tagNameObj, countObj);
+  } catch (e) {}
+
+  if (tagNameObj.value == "td")
+  {
+    // We are in a cell
+    gSelectedCellCount = countObj.value;
+    gCellElement = tableOrCellElement;
+    globalCellElement = gCellElement.cloneNode(false);
+
+    // Tells us whether cell, row, or column is selected
+    try {
+      gSelectedCellsType = gActiveEditor.getSelectedCellsType(gTableElement);
+    } catch (e) {}
+
+    // Ignore types except Cell, Row, and Column
+    if (gSelectedCellsType < SELECT_CELL || gSelectedCellsType > SELECT_COLUMN)
+      gSelectedCellsType = SELECT_CELL;
+
+    // Be sure at least 1 cell is selected.
+    // (If the count is 0, then we were inside the cell.)
+    if (gSelectedCellCount == 0)
+      DoCellSelection();
+
+    // Get location in the cell map
+    var rowIndexObj = { value: 0 };
+    var colIndexObj = { value: 0 };
+    try {
+      gActiveEditor.getCellIndexes(gCellElement, rowIndexObj, colIndexObj);
+    } catch (e) {}
+    gCurRowIndex = rowIndexObj.value;
+    gCurColIndex = colIndexObj.value;
+
+    // We save the current colspan to quickly
+    //  move selection from from cell to cell
+    if (GetCellData(gCurRowIndex, gCurColIndex))
+      gCurColSpan = gCellData.colSpan;
+
+    // Starting TabPanel name is passed in
+    if (window.arguments[1] == "CellPanel")
+      gDialog.TabBox.selectedTab = gDialog.CellTab;
+  }
+
+  if (gDialog.TabBox.selectedTab == gDialog.TableTab)
+  {
+    // We may call this with table selected, but no cell,
+    //  so disable the Cell Properties tab
+    if(!gCellElement)
+    {
+      // XXX: Disabling of tabs is currently broken, so for
+      //      now we'll just remove the tab completely.
+      //gDialog.CellTab.disabled = true;
+      gDialog.CellTab.parentNode.removeChild(gDialog.CellTab);
+    }
+  }
+
+  // Note: we must use gTableElement, not globalTableElement for these,
+  //  thus we should not put this in InitDialog.
+  // Instead, monitor desired counts with separate globals
+  var rowCountObj = { value: 0 };
+  var colCountObj = { value: 0 };
+  try {
+    gActiveEditor.getTableSize(gTableElement, rowCountObj, colCountObj);
+  } catch (e) {}
+
+  gRowCount = rowCountObj.value;
+  gLastRowIndex = gRowCount-1;
+  gColCount = colCountObj.value;
+  gLastColIndex = gColCount-1;
+
+
+  // Set appropriate icons and enable state for the Previous/Next buttons
+  SetSelectionButtons();
+
+  // If only one cell in table, disable change-selection widgets
+  if (gRowCount == 1 && gColCount == 1)
+    gDialog.SelectionList.setAttribute("disabled", "true");
+
+  // User can change these via textboxes
+  gNewRowCount = gRowCount;
+  gNewColCount = gColCount;
+
+  // This flag is used to control whether set check state
+  //  on "set attribute" checkboxes
+  // (Advanced Edit dialog use calls  InitDialog when done)
+  gAdvancedEditUsed = false;
+  InitDialog();
+  gAdvancedEditUsed = true;
+
+  // If first initializing, we really aren't changing anything
+  gCellDataChanged = false;
+
+  if (gDialog.TabBox.selectedTab == gDialog.CellTab)
+    setTimeout("gDialog.SelectionList.focus()", 0);
+  else
+    SetTextboxFocus(gDialog.TableRowsInput);
+
+  SetWindowLocation();
+}
+
+
+function InitDialog()
+{
+  // Get Table attributes
+  gDialog.TableRowsInput.value = gRowCount;
+  gDialog.TableColumnsInput.value = gColCount;
+  gDialog.TableWidthInput.value = InitPixelOrPercentMenulist(globalTableElement, gTableElement, "width", "TableWidthUnits", gPercent);
+  if (gUseCSS) {
+    gDialog.TableHeightInput.value = InitPixelOrPercentMenulist(globalTableElement, gTableElement, "height",
+                                                                "TableHeightUnits", gPercent);
+  }
+  gDialog.BorderWidthInput.value = globalTableElement.border;
+  gDialog.SpacingInput.value = globalTableElement.cellSpacing;
+  gDialog.PaddingInput.value = globalTableElement.cellPadding;
+
+  var marginLeft  = GetHTMLOrCSSStyleValue(globalTableElement, "align", "margin-left");
+  var marginRight = GetHTMLOrCSSStyleValue(globalTableElement, "align", "margin-right");
+  var halign = marginLeft.toLowerCase() + " " + marginRight.toLowerCase();
+  if (halign == "center center" || halign == "auto auto")
+    gDialog.TableAlignList.value = "center";
+  else if (halign == "right right" || halign == "auto 0px")
+    gDialog.TableAlignList.value = "right";
+  else // Default = left
+    gDialog.TableAlignList.value = "left";
+
+  // Be sure to get caption from table in doc, not the copied "globalTableElement"
+  gTableCaptionElement = gTableElement.caption;
+  if (gTableCaptionElement)
+  {
+    var align = GetHTMLOrCSSStyleValue(gTableCaptionElement, "align", "caption-side");
+    if (align != "bottom" && align != "left" && align != "right")
+      align = "top";
+    gDialog.TableCaptionList.value = align;
+  }
+
+  gTableColor = GetHTMLOrCSSStyleValue(globalTableElement, bgcolor, cssBackgroundColorStr);
+  gTableColor = ConvertRGBColorIntoHEXColor(gTableColor);
+  SetColor("tableBackgroundCW", gTableColor);
+
+  InitCellPanel();
+}
+
+function InitCellPanel()
+{
+  // Get cell attributes
+  if (globalCellElement)
+  {
+    // This assumes order of items is Cell, Row, Column
+    gDialog.SelectionList.value = gSelectedCellsType;
+
+    var previousValue = gDialog.CellHeightInput.value;
+    gDialog.CellHeightInput.value = InitPixelOrPercentMenulist(globalCellElement, gCellElement, "height", "CellHeightUnits", gPixel);
+    gDialog.CellHeightCheckbox.checked = gAdvancedEditUsed && previousValue != gDialog.CellHeightInput.value;
+
+    previousValue= gDialog.CellWidthInput.value;
+    gDialog.CellWidthInput.value = InitPixelOrPercentMenulist(globalCellElement, gCellElement, "width", "CellWidthUnits", gPixel);
+    gDialog.CellWidthCheckbox.checked = gAdvancedEditUsed && previousValue != gDialog.CellWidthInput.value;
+
+    var previousIndex = gDialog.CellVAlignList.selectedIndex;
+    var valign = GetHTMLOrCSSStyleValue(globalCellElement, "valign", "vertical-align").toLowerCase();
+    if (valign == topStr || valign == bottomStr)
+      gDialog.CellVAlignList.value = valign;
+    else // Default = middle
+      gDialog.CellVAlignList.value = defVAlign;
+
+    gDialog.CellVAlignCheckbox.checked = gAdvancedEditUsed && previousIndex != gDialog.CellVAlignList.selectedIndex;
+
+    previousIndex = gDialog.CellHAlignList.selectedIndex;
+
+    gAlignWasChar = false;
+
+    var halign = GetHTMLOrCSSStyleValue(globalCellElement, "align", "text-align").toLowerCase();
+    switch (halign)
+    {
+      case centerStr:
+      case rightStr:
+      case justifyStr:
+        gDialog.CellHAlignList.value = halign;
+        break;
+      case charStr:
+        // We don't support UI for this because layout doesn't work: bug 2212.
+        // Remember that's what they had so we don't change it
+        //  unless they change the alignment by using the menulist
+        gAlignWasChar = true;
+        // Fall through to use show default alignment in menu
+      default:
+        // Default depends on cell type (TH is "center", TD is "left")
+        gDialog.CellHAlignList.value =
+          (globalCellElement.nodeName.toLowerCase() == "th") ? "center" : "left";
+        break;
+    }
+
+    gDialog.CellHAlignCheckbox.checked = gAdvancedEditUsed &&
+      previousIndex != gDialog.CellHAlignList.selectedIndex;
+
+    previousIndex = gDialog.CellStyleList.selectedIndex;
+    gDialog.CellStyleList.value = globalCellElement.nodeName.toLowerCase();
+    gDialog.CellStyleCheckbox.checked = gAdvancedEditUsed && previousIndex != gDialog.CellStyleList.selectedIndex;
+
+    previousIndex = gDialog.TextWrapList.selectedIndex;
+    if (GetHTMLOrCSSStyleValue(globalCellElement, "nowrap", "white-space") == "nowrap")
+      gDialog.TextWrapList.value = "nowrap";
+    else
+      gDialog.TextWrapList.value = "wrap";
+    gDialog.TextWrapCheckbox.checked = gAdvancedEditUsed && previousIndex != gDialog.TextWrapList.selectedIndex;
+
+    previousValue = gCellColor;
+    gCellColor = GetHTMLOrCSSStyleValue(globalCellElement, bgcolor, cssBackgroundColorStr);
+    gCellColor = ConvertRGBColorIntoHEXColor(gCellColor);
+    SetColor("cellBackgroundCW", gCellColor);
+    gDialog.CellColorCheckbox.checked = gAdvancedEditUsed && previousValue != gCellColor;
+
+    // We want to set this true in case changes came
+    //   from Advanced Edit dialog session (must assume something changed)
+    gCellDataChanged = true;
+  }
+}
+
+function GetCellData(rowIndex, colIndex)
+{
+  // Get actual rowspan and colspan
+  var startRowIndexObj = { value: 0 };
+  var startColIndexObj = { value: 0 };
+  var rowSpanObj = { value: 0 };
+  var colSpanObj = { value: 0 };
+  var actualRowSpanObj = { value: 0 };
+  var actualColSpanObj = { value: 0 };
+  var isSelectedObj = { value: false };
+
+  try {
+    gActiveEditor.getCellDataAt(gTableElement, rowIndex, colIndex,
+                         gCellData,
+                         startRowIndexObj, startColIndexObj,
+                         rowSpanObj, colSpanObj,
+                         actualRowSpanObj, actualColSpanObj, isSelectedObj);
+    // We didn't find a cell
+    if (!gCellData.value) return false;
+  }
+  catch(ex) {
+    return false;
+  }
+
+  gCellData.startRowIndex = startRowIndexObj.value;
+  gCellData.startColIndex = startColIndexObj.value;
+  gCellData.rowSpan = rowSpanObj.value;
+  gCellData.colSpan = colSpanObj.value;
+  gCellData.actualRowSpan = actualRowSpanObj.value;
+  gCellData.actualColSpan = actualColSpanObj.value;
+  gCellData.isSelected = isSelectedObj.value;
+  return true;
+}
+
+function SelectCellHAlign()
+{
+  SetCheckbox("CellHAlignCheckbox");
+  // Once user changes the alignment,
+  //  we lose their original "CharAt" alignment"
+  gAlignWasChar = false;
+}
+
+function GetColorAndUpdate(ColorWellID)
+{
+  var colorWell = document.getElementById(ColorWellID);
+  if (!colorWell) return;
+
+  var colorObj = { Type:"", TableColor:0, CellColor:0, NoDefault:false, Cancel:false, BackgroundColor:0 };
+
+  switch( ColorWellID )
+  {
+    case "tableBackgroundCW":
+      colorObj.Type = "Table";
+      colorObj.TableColor = gTableColor;
+      break;
+    case "cellBackgroundCW":
+      colorObj.Type = "Cell";
+      colorObj.CellColor = gCellColor;
+      break;
+  }
+  window.openDialog("chrome://editor/content/EdColorPicker.xul", "_blank", "chrome,close,titlebar,modal", "", colorObj);
+
+  // User canceled the dialog
+  if (colorObj.Cancel)
+    return;
+
+  switch( ColorWellID )
+  {
+    case "tableBackgroundCW":
+      gTableColor = colorObj.BackgroundColor;
+      SetColor(ColorWellID, gTableColor);
+      break;
+    case "cellBackgroundCW":
+      gCellColor = colorObj.BackgroundColor;
+      SetColor(ColorWellID, gCellColor);
+      SetCheckbox('CellColorCheckbox');
+      break;
+  }
+}
+
+function SetColor(ColorWellID, color)
+{
+  // Save the color
+  if (ColorWellID == "cellBackgroundCW")
+  {
+    if (color)
+    {
+      try {
+        gActiveEditor.setAttributeOrEquivalent(globalCellElement, bgcolor,
+                                               color, true);
+      } catch(e) {}
+      gDialog.CellInheritColor.collapsed = true;
+    }
+    else
+    {
+      try {
+        gActiveEditor.removeAttributeOrEquivalent(globalCellElement, bgcolor, true);
+      } catch(e) {}
+      // Reveal addition message explaining "default" color
+      gDialog.CellInheritColor.collapsed = false;
+    }
+  }
+  else
+  {
+    if (color)
+    {
+      try {
+        gActiveEditor.setAttributeOrEquivalent(globalTableElement, bgcolor,
+                                               color, true);
+      } catch(e) {}
+      gDialog.TableInheritColor.collapsed = true;
+    }
+    else
+    {
+      try {
+        gActiveEditor.removeAttributeOrEquivalent(globalTableElement, bgcolor, true);
+      } catch(e) {}
+      gDialog.TableInheritColor.collapsed = false;
+    }
+    SetCheckbox('CellColorCheckbox');
+  }
+
+  setColorWell(ColorWellID, color);
+}
+
+function ChangeSelectionToFirstCell()
+{
+  if (!GetCellData(0,0))
+  {
+    dump("Can't find first cell in table!\n");
+    return;
+  }
+  gCellElement = gCellData.value;
+  globalCellElement = gCellElement;
+
+  gCurRowIndex = 0;
+  gCurColIndex = 0;
+  ChangeSelection(RESET_SELECTION);
+}
+
+function ChangeSelection(newType)
+{
+  newType = Number(newType);
+
+  if (gSelectedCellsType == newType)
+    return;
+
+  if (newType == RESET_SELECTION)
+    // Restore selection to existing focus cell
+    gSelection.collapse(gCellElement,0);
+  else
+    gSelectedCellsType = newType;
+
+  // Keep the same focus gCellElement, just change the type
+  DoCellSelection();
+  SetSelectionButtons();
+
+  // Note: globalCellElement should still be a clone of gCellElement
+}
+
+function MoveSelection(forward)
+{
+  var newRowIndex = gCurRowIndex;
+  var newColIndex = gCurColIndex;
+  var focusCell;
+  var inRow = false;
+
+  if (gSelectedCellsType == SELECT_ROW)
+  {
+    newRowIndex += (forward ? 1 : -1);
+
+    // Wrap around if before first or after last row
+    if (newRowIndex < 0)
+      newRowIndex = gLastRowIndex;
+    else if (newRowIndex > gLastRowIndex)
+      newRowIndex = 0;
+    inRow = true;
+
+    // Use first cell in row for focus cell
+    newColIndex = 0;
+  }
+  else
+  {
+    // Cell or column:
+    if (!forward)
+      newColIndex--;
+
+    if (gSelectedCellsType == SELECT_CELL)
+    {
+      // Skip to next cell
+      if (forward)
+        newColIndex += gCurColSpan;
+    }
+    else  // SELECT_COLUMN
+    {
+      // Use first cell in column for focus cell
+      newRowIndex = 0;
+
+      // Don't skip by colspan,
+      //  but find first cell in next cellmap column
+      if (forward)
+        newColIndex++;
+    }
+
+    if (newColIndex < 0)
+    {
+      // Request is before the first cell in column
+
+      // Wrap to last cell in column
+      newColIndex = gLastColIndex;
+
+      if (gSelectedCellsType == SELECT_CELL)
+      {
+        // If moving by cell, also wrap to previous...
+        if (newRowIndex > 0)
+          newRowIndex -= 1;
+        else
+          // ...or the last row
+          newRowIndex = gLastRowIndex;
+
+        inRow = true;
+      }
+    }
+    else if (newColIndex > gLastColIndex)
+    {
+      // Request is after the last cell in column
+
+      // Wrap to first cell in column
+      newColIndex = 0;
+
+      if (gSelectedCellsType == SELECT_CELL)
+      {
+        // If moving by cell, also wrap to next...
+        if (newRowIndex < gLastRowIndex)
+          newRowIndex++;
+        else
+          // ...or the first row
+          newRowIndex = 0;
+
+        inRow = true;
+      }
+    }
+  }
+
+  // Get the cell at the new location
+  do {
+    if (!GetCellData(newRowIndex, newColIndex))
+    {
+      dump("MoveSelection: CELL NOT FOUND\n");
+      return;
+    }
+    if (inRow)
+    {
+      if (gCellData.startRowIndex == newRowIndex)
+        break;
+      else
+        // Cell spans from a row above, look for the next cell in row
+        newRowIndex += gCellData.actualRowSpan;
+    }
+    else
+    {
+      if (gCellData.startColIndex == newColIndex)
+        break;
+      else
+        // Cell spans from a Col above, look for the next cell in column
+        newColIndex += gCellData.actualColSpan;
+    }
+  }
+  while(true);
+
+  // Save data for current selection before changing
+  if (gCellDataChanged) // && gDialog.ApplyBeforeMove.checked)
+  {
+    if (!ValidateCellData())
+      return;
+
+    gActiveEditor.beginTransaction();
+    // Apply changes to all selected cells
+    ApplyCellAttributes();
+    gActiveEditor.endTransaction();
+
+    SetCloseButton();
+  }
+
+  // Set cell and other data for new selection
+  gCellElement = gCellData.value;
+
+  // Save globals for new current cell
+  gCurRowIndex = gCellData.startRowIndex;
+  gCurColIndex = gCellData.startColIndex;
+  gCurColSpan = gCellData.actualColSpan;
+
+  // Copy for new global cell
+  globalCellElement = gCellElement.cloneNode(false);
+
+  // Change the selection
+  DoCellSelection();
+
+  // Scroll page so new selection is visible
+  // Using SELECTION_ANCHOR_REGION makes the upper-left corner of first selected cell
+  //    the point to bring into view.
+  try {
+    var selectionController = gActiveEditor.selectionController;
+    selectionController.scrollSelectionIntoView(selectionController.SELECTION_NORMAL, selectionController.SELECTION_ANCHOR_REGION, true);
+  } catch (e) {}
+
+  // Reinitialize dialog using new cell
+//  if (!gDialog.KeepCurrentData.checked)
+  // Setting this false unchecks all "set attributes" checkboxes
+  gAdvancedEditUsed = false;
+  InitCellPanel();
+  gAdvancedEditUsed = true;
+}
+
+
+function DoCellSelection()
+{
+  // Collapse selection into to the focus cell
+  //  so editor uses that as start cell
+  gSelection.collapse(gCellElement, 0);
+
+  var tagNameObj = { value: "" };
+  var countObj = { value: 0 };
+  try {
+    switch (gSelectedCellsType)
+    {
+      case SELECT_CELL:
+        gActiveEditor.selectTableCell();
+        break
+      case SELECT_ROW:
+        gActiveEditor.selectTableRow();
+        break;
+      default:
+        gActiveEditor.selectTableColumn();
+        break;
+    }
+    // Get number of cells selected
+    var tableOrCellElement = gActiveEditor.getSelectedOrParentTableElement(tagNameObj, countObj);
+  } catch (e) {}
+
+  if (tagNameObj.value == "td")
+    gSelectedCellCount = countObj.value;
+  else
+    gSelectedCellCount = 0;
+
+  // Currently, we can only allow advanced editing on ONE cell element at a time
+  //   else we ignore CSS, JS, and HTML attributes not already in dialog
+  SetElementEnabled(gDialog.AdvancedEditCell, gSelectedCellCount == 1);
+
+  gDialog.AdvancedEditCell.setAttribute("tooltiptext", 
+    gSelectedCellCount > 1 ? GetString("AdvancedEditForCellMsg") :
+                             gDialog.AdvancedEditCellToolTipText);
+}
+
+function SetSelectionButtons()
+{
+  if (gSelectedCellsType == SELECT_ROW)
+  {
+    // Trigger CSS to set images of up and down arrows
+    gDialog.PreviousButton.setAttribute("type","row");
+    gDialog.NextButton.setAttribute("type","row");
+  }
+  else
+  {
+    // or images of left and right arrows
+    gDialog.PreviousButton.setAttribute("type","col");
+    gDialog.NextButton.setAttribute("type","col");
+  }
+  DisableSelectionButtons((gSelectedCellsType == SELECT_ROW && gRowCount == 1) ||
+                          (gSelectedCellsType == SELECT_COLUMN && gColCount == 1) ||
+                          (gRowCount == 1 && gColCount == 1));
+}
+
+function DisableSelectionButtons( disable )
+{
+  gDialog.PreviousButton.setAttribute("disabled", disable ? "true" : "false");
+  gDialog.NextButton.setAttribute("disabled", disable ? "true" : "false");
+}
+
+function SwitchToValidatePanel()
+{
+  if (gDialog.TabBox.selectedTab != gValidateTab)
+    gDialog.TabBox.selectedTab = gValidateTab;
+}
+
+function SetAlign(listID, defaultValue, element, attName)
+{
+  var value = document.getElementById(listID).value;
+  if (value == defaultValue)
+  {
+    try {
+      gActiveEditor.removeAttributeOrEquivalent(element, attName, true);
+    } catch(e) {}
+  }
+  else
+  {
+    try {
+      gActiveEditor.setAttributeOrEquivalent(element, attName, value, true);
+    } catch(e) {}
+  }
+}
+
+function ValidateTableData()
+{
+  gValidateTab = gDialog.TableTab;
+  gNewRowCount = Number(ValidateNumber(gDialog.TableRowsInput, null, 1, gMaxRows, null, true, true));
+  if (gValidationError) return false;
+
+  gNewColCount = Number(ValidateNumber(gDialog.TableColumnsInput, null, 1, gMaxColumns, null, true, true));
+  if (gValidationError) return false;
+
+  // If user is deleting any cells, get confirmation
+  // (This is a global to the dialog and we ask only once per dialog session)
+  if ( !gCanDelete &&
+        (gNewRowCount < gRowCount ||
+         gNewColCount < gColCount) ) 
+  {
+    if (ConfirmWithTitle(GetString("DeleteTableTitle"), 
+                         GetString("DeleteTableMsg"),
+                         GetString("DeleteCells")) )
+    {
+      gCanDelete = true;
+    }
+    else
+    {
+      SetTextboxFocus(gNewRowCount < gRowCount ? gDialog.TableRowsInput : gDialog.TableColumnsInput);
+      return false;
+    }
+  }
+
+  ValidateNumber(gDialog.TableWidthInput, gDialog.TableWidthUnits,
+                 1, gMaxTableSize, globalTableElement, "width");
+  if (gValidationError) return false;
+
+  if (gUseCSS) {
+    ValidateNumber(gDialog.TableHeightInput, gDialog.TableHeightUnits,
+                   1, gMaxTableSize, globalTableElement, "height");
+    if (gValidationError) return false;
+  }
+
+  var border = ValidateNumber(gDialog.BorderWidthInput, null, 0, gMaxPixels, globalTableElement, "border");
+  // TODO: Deal with "BORDER" without value issue
+  if (gValidationError) return false;
+
+  ValidateNumber(gDialog.SpacingInput, null, 0, gMaxPixels, globalTableElement, "cellspacing");
+  if (gValidationError) return false;
+
+  ValidateNumber(gDialog.PaddingInput, null, 0, gMaxPixels, globalTableElement, "cellpadding");
+  if (gValidationError) return false;
+
+  SetAlign("TableAlignList", defHAlign, globalTableElement, "align");
+
+  // Color is set on globalCellElement immediately
+  return true;
+}
+
+function ValidateCellData()
+{
+
+  gValidateTab = gDialog.CellTab;
+
+  if (gDialog.CellHeightCheckbox.checked)
+  {
+    ValidateNumber(gDialog.CellHeightInput, gDialog.CellHeightUnits,
+                    1, gMaxTableSize, globalCellElement, "height");
+    if (gValidationError) return false;
+  }
+
+  if (gDialog.CellWidthCheckbox.checked)
+  {
+    ValidateNumber(gDialog.CellWidthInput, gDialog.CellWidthUnits,
+                   1, gMaxTableSize, globalCellElement, "width");
+    if (gValidationError) return false;
+  }
+
+  if (gDialog.CellHAlignCheckbox.checked)
+  {
+    var hAlign = gDialog.CellHAlignList.value;
+
+    // Horizontal alignment is complicated by "char" type
+    // We don't change current values if user didn't edit alignment
+    if (!gAlignWasChar)
+    {
+      globalCellElement.removeAttribute(charStr);
+
+      // Always set "align" attribute,
+      //  so the default "left" is effective in a cell
+      //  when parent row has align set.
+      globalCellElement.setAttribute("align", hAlign);
+    }
+  }
+
+  if (gDialog.CellVAlignCheckbox.checked)
+  {
+    // Always set valign (no default in 2nd param) so
+    //  the default "middle" is effective in a cell
+    //  when parent row has valign set.
+    SetAlign("CellVAlignList", "", globalCellElement, "valign");
+  }
+
+  if (gDialog.TextWrapCheckbox.checked)
+  {
+    if (gDialog.TextWrapList.value == "nowrap")
+      try {
+        gActiveEditor.setAttributeOrEquivalent(globalCellElement, "nowrap",
+                                               "nowrap", true);
+      } catch(e) {}
+    else
+      try {
+        gActiveEditor.removeAttributeOrEquivalent(globalCellElement, "nowrap", true);
+      } catch(e) {}
+  }
+
+  return true;
+}
+
+function ValidateData()
+{
+  var result;
+
+  // Validate current panel first
+  if (gDialog.TabBox.selectedTab == gDialog.TableTab)
+  {
+    result = ValidateTableData();
+    if (result)
+      result = ValidateCellData();
+  } else {
+    result = ValidateCellData();
+    if (result)
+      result = ValidateTableData();
+  }
+  if(!result) return false;
+
+  // Set global element for AdvancedEdit
+  if(gDialog.TabBox.selectedTab == gDialog.TableTab)
+    globalElement = globalTableElement;
+  else
+    globalElement = globalCellElement;
+
+  return true;
+}
+
+function ChangeCellTextbox(textboxID)
+{
+  // Filter input for just integers
+  forceInteger(textboxID);
+
+  if (gDialog.TabBox.selectedTab == gDialog.CellTab)
+    gCellDataChanged = true;
+}
+
+// Call this when a textbox or menulist is changed
+//   so the checkbox is automatically set
+function SetCheckbox(checkboxID)
+{
+  if (checkboxID && checkboxID.length > 0)
+  {
+    // Set associated checkbox
+    document.getElementById(checkboxID).checked = true;
+  }
+  gCellDataChanged = true;
+}
+
+function ChangeIntTextbox(textboxID, checkboxID)
+{
+  // Filter input for just integers
+  forceInteger(textboxID);
+
+  // Set associated checkbox
+  SetCheckbox(checkboxID);
+}
+
+function CloneAttribute(destElement, srcElement, attr)
+{
+  var value = srcElement.getAttribute(attr);
+  // Use editor methods since we are always
+  //  modifying a table in the document and
+  //  we need transaction system for undo
+  try {
+    if (!value || value.length == 0)
+      gActiveEditor.removeAttributeOrEquivalent(destElement, attr, false);
+    else
+      gActiveEditor.setAttributeOrEquivalent(destElement, attr, value, false);
+  } catch(e) {}
+}
+
+function ApplyTableAttributes()
+{
+  var newAlign = gDialog.TableCaptionList.value;
+  if (!newAlign) newAlign = "";
+
+  if (gTableCaptionElement)
+  {
+    // Get current alignment
+    var align = GetHTMLOrCSSStyleValue(gTableCaptionElement, "align", "caption-side").toLowerCase();
+    // This is the default
+    if (!align) align = "top";
+
+    if (newAlign == "")
+    {
+      // Remove existing caption
+      try {
+        gActiveEditor.deleteNode(gTableCaptionElement);
+      } catch(e) {}
+      gTableCaptionElement = null;
+    }
+    else if(newAlign != align)
+    {
+      try {
+        if (newAlign == "top") // This is default, so don't explicitly set it
+          gActiveEditor.removeAttributeOrEquivalent(gTableCaptionElement, "align", false);
+        else
+          gActiveEditor.setAttributeOrEquivalent(gTableCaptionElement, "align", newAlign, false);
+      } catch(e) {}
+    }
+  }
+  else if (newAlign != "")
+  {
+    // Create and insert a caption:
+    try {
+      gTableCaptionElement = gActiveEditor.createElementWithDefaults("caption");
+    } catch (e) {}
+    if (gTableCaptionElement)
+    {
+      if (newAlign != "top")
+        gTableCaptionElement.setAttribute("align", newAlign);
+
+      // Insert it into the table - caption is always inserted as first child
+      try {
+        gActiveEditor.insertNode(gTableCaptionElement, gTableElement, 0);
+      } catch(e) {}
+
+      // Put selecton back where it was
+      ChangeSelection(RESET_SELECTION);
+    }
+  }
+
+  var countDelta;
+  var foundCell;
+  var i;
+
+  if (gNewRowCount != gRowCount)
+  {
+    countDelta = gNewRowCount - gRowCount;
+    if (gNewRowCount > gRowCount)
+    {
+      // Append new rows
+      // Find first cell in last row
+      if(GetCellData(gLastRowIndex, 0))
+      {
+        try {
+          // Move selection to the last cell
+          gSelection.collapse(gCellData.value,0);
+          // Insert new rows after it
+          gActiveEditor.insertTableRow(countDelta, true);
+          gRowCount = gNewRowCount;
+          gLastRowIndex = gRowCount - 1;
+          // Put selecton back where it was
+          ChangeSelection(RESET_SELECTION);
+        }
+        catch(ex) {
+          dump("FAILED TO FIND FIRST CELL IN LAST ROW\n");
+        }
+      }
+    }
+    else
+    {
+      // Delete rows
+      if (gCanDelete)
+      {
+        // Find first cell starting in first row we delete
+        var firstDeleteRow = gRowCount + countDelta;
+        foundCell = false;
+        for ( i = 0; i <= gLastColIndex; i++)
+        {
+          if (!GetCellData(firstDeleteRow, i))
+            break; // We failed to find a cell
+
+          if (gCellData.startRowIndex == firstDeleteRow)
+          {
+            foundCell = true;
+            break;
+          }
+        };
+        if (foundCell)
+        {
+          try {
+            // Move selection to the cell we found
+            gSelection.collapse(gCellData.value, 0);
+            gActiveEditor.deleteTableRow(-countDelta);
+            gRowCount = gNewRowCount;
+            gLastRowIndex = gRowCount - 1;
+            if (gCurRowIndex > gLastRowIndex)
+              // We are deleting our selection
+              // move it to start of table
+              ChangeSelectionToFirstCell()
+            else
+              // Put selecton back where it was
+              ChangeSelection(RESET_SELECTION);
+          }
+          catch(ex) {
+            dump("FAILED TO FIND FIRST CELL IN LAST ROW\n");
+          }
+        }
+      }
+    }
+  }
+
+  if (gNewColCount != gColCount)
+  {
+    countDelta = gNewColCount - gColCount;
+
+    if (gNewColCount > gColCount)
+    {
+      // Append new columns
+      // Find last cell in first column
+      if(GetCellData(0, gLastColIndex))
+      {
+        try {
+          // Move selection to the last cell
+          gSelection.collapse(gCellData.value,0);
+          gActiveEditor.insertTableColumn(countDelta, true);
+          gColCount = gNewColCount;
+          gLastColIndex = gColCount-1;
+          // Restore selection
+          ChangeSelection(RESET_SELECTION);
+        }
+        catch(ex) {
+          dump("FAILED TO FIND FIRST CELL IN LAST COLUMN\n");
+        }
+      }
+    }
+    else
+    {
+      // Delete columns
+      if (gCanDelete)
+      {
+        var firstDeleteCol = gColCount + countDelta;
+        foundCell = false;
+        for ( i = 0; i <= gLastRowIndex; i++)
+        {
+          // Find first cell starting in first column we delete
+          if (!GetCellData(i, firstDeleteCol))
+            break; // We failed to find a cell
+
+          if (gCellData.startColIndex == firstDeleteCol)
+          {
+            foundCell = true;
+            break;
+          }
+        };
+        if (foundCell)
+        {
+          try {
+            // Move selection to the cell we found
+            gSelection.collapse(gCellData.value, 0);
+            gActiveEditor.deleteTableColumn(-countDelta);
+            gColCount = gNewColCount;
+            gLastColIndex = gColCount-1;
+            if (gCurColIndex > gLastColIndex)
+              ChangeSelectionToFirstCell()
+            else
+              ChangeSelection(RESET_SELECTION);
+          }
+          catch(ex) {
+            dump("FAILED TO FIND FIRST CELL IN LAST ROW\n");
+          }
+        }
+      }
+    }
+  }
+
+  // Clone all remaining attributes to pick up
+  //  anything changed by Advanced Edit Dialog
+  try {
+    gActiveEditor.cloneAttributes(gTableElement, globalTableElement);
+  } catch(e) {}
+}
+
+function ApplyCellAttributes()
+{
+  var rangeObj = { value: null };
+  var selectedCell;
+  try {
+    selectedCell = gActiveEditor.getFirstSelectedCell(rangeObj);
+  } catch(e) {}
+
+  if (!selectedCell)
+    return;
+
+  if (gSelectedCellCount == 1)
+  {
+    // When only one cell is selected, simply clone entire element,
+    //  thus CSS and JS from Advanced edit is copied
+    try {
+      gActiveEditor.cloneAttributes(selectedCell, globalCellElement);
+    } catch(e) {}
+
+    if (gDialog.CellStyleCheckbox.checked)
+    {
+      var currentStyleIndex = (selectedCell.nodeName.toLowerCase() == "th") ? 1 : 0;
+      if (gDialog.CellStyleList.selectedIndex != currentStyleIndex)
+      {
+        // Switch cell types
+        // (replaces with new cell and copies attributes and contents)
+        try {
+          selectedCell = gActiveEditor.switchTableCellHeaderType(selectedCell);
+        } catch(e) {}
+      }
+    }
+  }
+  else
+  {
+    // Apply changes to all selected cells
+    //XXX THIS DOESN'T COPY ADVANCED EDIT CHANGES!
+    try {
+      while (selectedCell)
+      {
+        ApplyAttributesToOneCell(selectedCell);
+        selectedCell = gActiveEditor.getNextSelectedCell(rangeObj);
+      }
+    } catch(e) {}
+  }
+  gCellDataChanged = false;
+}
+
+function ApplyAttributesToOneCell(destElement)
+{
+  if (gDialog.CellHeightCheckbox.checked)
+    CloneAttribute(destElement, globalCellElement, "height");
+
+  if (gDialog.CellWidthCheckbox.checked)
+    CloneAttribute(destElement, globalCellElement, "width");
+
+  if (gDialog.CellHAlignCheckbox.checked)
+  {
+    CloneAttribute(destElement, globalCellElement, "align");
+    CloneAttribute(destElement, globalCellElement, charStr);
+  }
+
+  if (gDialog.CellVAlignCheckbox.checked)
+    CloneAttribute(destElement, globalCellElement, "valign");
+
+  if (gDialog.TextWrapCheckbox.checked)
+    CloneAttribute(destElement, globalCellElement, "nowrap");
+
+  if (gDialog.CellStyleCheckbox.checked)
+  {
+    var newStyleIndex = gDialog.CellStyleList.selectedIndex;
+    var currentStyleIndex = (destElement.nodeName.toLowerCase() == "th") ? 1 : 0;
+
+    if (newStyleIndex != currentStyleIndex)
+    {
+      // Switch cell types
+      // (replaces with new cell and copies attributes and contents)
+      try {
+        destElement = gActiveEditor.switchTableCellHeaderType(destElement);
+      } catch(e) {}
+    }
+  }
+
+  if (gDialog.CellColorCheckbox.checked)
+    CloneAttribute(destElement, globalCellElement, "bgcolor");
+}
+
+function SetCloseButton()
+{
+  // Change text on "Cancel" button after Apply is used
+  if (!gApplyUsed)
+  {
+    document.documentElement.setAttribute("buttonlabelcancel",
+      document.documentElement.getAttribute("buttonlabelclose"));
+    gApplyUsed = true;
+  }
+}
+
+function Apply()
+{
+  if (ValidateData())
+  {
+    gActiveEditor.beginTransaction();
+
+    ApplyTableAttributes();
+
+    // We may have just a table, so check for cell element
+    if (globalCellElement)
+      ApplyCellAttributes();
+
+    gActiveEditor.endTransaction();
+
+    SetCloseButton();
+    return true;
+  }
+  return false;
+}
+
+function onAccept()
+{
+  // Do same as Apply and close window if ValidateData succeeded
+  var retVal = Apply();
+  if (retVal)
+    SaveWindowLocation();
+
+  return retVal;
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdTableProps.xul
@@ -0,0 +1,288 @@
+<?xml version="1.0"?>
+
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -   Ben Goodger
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?> 
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorTableProperties.dtd">
+
+<dialog title="&tableWindow.title;"
+    id="tableDlg"
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    onload="Startup()"
+    buttons="accept,extra1,cancel"
+    buttonlabelclose="&closeButton.label;"
+    buttonlabelextra1="&applyButton.label;"
+    buttonaccesskeyextra1="&applyButton.accesskey;"
+    ondialogaccept="return onAccept();"
+    ondialogextra1="return Apply();"
+    ondialogcancel="return onCancel();">
+
+  <!-- Methods common to all editor dialogs -->
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdTableProps.js"/>
+
+  <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+  <broadcaster id="args" value=""/>
+
+  <tabbox id="TabBox">
+    <tabs flex="1">
+      <tab id="TableTab" label="&tableTab.label;"/>
+      <tab id="CellTab" label="&cellTab.label;"/>
+    </tabs>
+    <tabpanels>
+
+      <!-- TABLE PANEL -->
+      <vbox>
+        <groupbox orient="horizontal"><caption label="&size.label;"/>
+          <grid>
+            <columns><column/><column/><column/><column/><column/></columns>
+              <rows>
+                <row align="center">
+                  <label value="&tableRows.label;" accesskey="&tableRows.accessKey;" control="TableRowsInput"/>
+                  <textbox class="narrow" id="TableRowsInput" oninput="forceInteger(this.id);"/>
+                  <spring class="bigspacer"/>
+                  <label value="&tableHeight.label;" accesskey="&tableHeight.accessKey;"
+                         id="TableHeightLabel" control="TableHeightInput"/>
+                  <textbox class="narrow" id="TableHeightInput" oninput="forceInteger(this.id);"/>
+                  <menulist id="TableHeightUnits"/>
+                </row>
+              <row align="center">
+                <label value="&tableColumns.label;" accesskey="&tableColumns.accessKey;" control="TableColumnsInput"/>
+                <textbox class="narrow" id="TableColumnsInput" oninput="forceInteger(this.id);"/>
+                <spring class="bigspacer"/>
+                <label value="&tableWidth.label;" accesskey="&tableWidth.accessKey;" control="TableWidthInput"/>
+                <textbox class="narrow" id="TableWidthInput" oninput="forceInteger(this.id);"/>
+                <menulist id="TableWidthUnits"/>
+              </row>
+            </rows>
+            <!-- KEEP GRID LAYOUT here since we will be adding back support for table HEIGHT via CSS -->
+          </grid>
+        </groupbox>
+        <groupbox><caption label="&tableBorderSpacing.label;"/>
+        <grid>
+          <columns><column/><column/><column/></columns>
+          <rows>
+            <row align="center">
+              <label control="BorderWidthInput"
+                     value="&tableBorderWidth.label;"
+                     accesskey="&tableBorderWidth.accessKey;"/>
+              <textbox class="narrow" id="BorderWidthInput" oninput="forceInteger(this.id);"/>
+              <label align="left" value="&pixels.label;"/>
+            </row>
+            <row align="center">
+              <label control="SpacingInput"
+                     value="&tableSpacing.label;"
+                     accesskey="&tableSpacing.accessKey;"/>
+              <textbox class="narrow" id="SpacingInput" oninput="forceInteger(this.id);"/>
+              <label value="&tablePxBetwCells.label;"/>
+            </row>
+            <row align="center">
+              <label control="PaddingInput"
+                     value="&tablePadding.label;"
+                     accesskey="&tablePadding.accessKey;"/>
+              <textbox class="narrow" id="PaddingInput" oninput="forceInteger(this.id);"/>
+              <label value="&tablePxBetwBrdrCellContent.label;"/>
+            </row>
+          </rows>
+        </grid>
+        </groupbox>
+        <!-- Table Alignment and Caption -->
+        <hbox flex="1" align="center">
+          <label control="TableAlignList"
+                 value="&tableAlignment.label;"
+                 accesskey="&tableAlignment.accessKey;"/>
+          <menulist id="TableAlignList">
+            <menupopup>
+              <menuitem label="&AlignLeft.label;"   value="left"/>
+              <menuitem label="&AlignCenter.label;" value="center"/>
+              <menuitem label="&AlignRight.label;"  value="right"/>
+            </menupopup>
+          </menulist>
+          <spacer class="spacer"/>
+          <label control="TableCaptionList"
+                 value="&tableCaption.label;"
+                 accesskey="&tableCaption.accessKey;"/>
+          <menulist id="TableCaptionList">
+            <menupopup>
+              <menuitem label="&tableCaptionNone.label;"  value=""/>
+              <menuitem label="&tableCaptionAbove.label;" value="top"/>
+              <menuitem label="&tableCaptionBelow.label;" value="bottom"/>
+              <menuitem label="&tableCaptionLeft.label;"  value="left"/>
+              <menuitem label="&tableCaptionRight.label;" value="right"/>
+            </menupopup>
+          </menulist>
+        </hbox>
+        <separator class="groove"/>
+        <hbox align="center">
+          <label value="&backgroundColor.label;"/>
+          <button id="tableBackground" class="color-button" oncommand="GetColorAndUpdate('tableBackgroundCW');">
+            <spacer id="tableBackgroundCW" class="color-well"/>
+          </button>
+          <spacer class="spacer"/>
+          <label id="TableInheritColor" value="&tableInheritColor.label;" collapsed="true"/>
+        </hbox>
+        <separator class="groove"/>
+        <hbox flex="1" align="center">
+          <spacer flex="1"/>
+          <!-- From EdDialogOvlerlay.xul -->
+          <button id="AdvancedEditButton"/>
+        </hbox>
+        <spacer flex="1"/>
+      </vbox><!-- Table Panel -->
+
+      <!-- CELL PANEL -->
+      <vbox>
+        <groupbox orient="horizontal" align="center">
+          <caption label="&cellSelection.label;"/>
+          <vbox>
+            <menulist id="SelectionList" oncommand="ChangeSelection(event.target.value)" flex="1">
+              <menupopup>
+                <!-- JS code assumes order is Cell, Row, Column -->
+                <menuitem label="&cellSelectCell.label;"   value="1"/>
+                <menuitem label="&cellSelectRow.label;"    value="2"/>
+                <menuitem label="&cellSelectColumn.label;" value="3"/>
+              </menupopup>
+            </menulist>
+            <hbox flex="1">
+              <button id="PreviousButton" label="&cellSelectPrevious.label;" accesskey="&cellSelectPrevious.accessKey;" oncommand="MoveSelection(0)" flex="1"/>
+              <button id="NextButton" class="align-right" label="&cellSelectNext.label;" accesskey="&cellSelectNext.accessKey;" oncommand="MoveSelection(1)" flex="1"/>
+            </hbox>
+          </vbox>
+          <spacer class="bigspacer"/>
+          <vbox flex="1">
+            <label value="&applyBeforeChange1.label;"/>
+            <label value="&applyBeforeChange2.label;"/>
+          </vbox>
+        </groupbox>
+        <hbox align="center">
+          <!-- cell size groupbox -->
+          <groupbox><caption label="&size.label;"/>
+            <grid>
+              <columns><column/><column/><column flex="1"/></columns>
+              <rows>
+                <row align="center">
+                  <checkbox id="CellHeightCheckbox" label="&tableHeight.label;" accesskey="&tableHeight.accessKey;"/>
+                  <textbox class="narrow" id="CellHeightInput"
+                           oninput="ChangeIntTextbox(this.id,'CellHeightCheckbox');"/>
+                  <menulist id="CellHeightUnits" oncommand="SetCheckbox('CellHeightCheckbox');"/>
+                </row>
+                <row align="center">
+                  <checkbox id="CellWidthCheckbox" label="&tableWidth.label;" accesskey="&tableWidth.accessKey;"/>
+                  <textbox class="narrow" id="CellWidthInput"
+                           oninput="ChangeIntTextbox(this.id,'CellWidthCheckbox');"/>
+                  <menulist id="CellWidthUnits" oncommand="SetCheckbox('CellWidthCheckbox');"/>
+                </row>
+              </rows>
+            </grid>
+            <spacer class="bigspacer"/>
+          </groupbox>
+          <!-- Alignment -->
+          <groupbox><caption label="&cellContentAlignment.label;"/>
+            <grid>
+              <columns><column/><column flex="1"/><column/></columns>
+              <rows>
+                <row align="center">
+                  <checkbox id="CellVAlignCheckbox" label="&cellVertical.label;" accesskey="&cellVertical.accessKey;"/>
+                  <menulist id="CellVAlignList" oncommand="SetCheckbox('CellVAlignCheckbox');">
+                    <menupopup>
+                      <menuitem label="&cellAlignTop.label;"    value="top"/>
+                      <menuitem label="&cellAlignMiddle.label;" value="middle"/>
+                      <menuitem label="&cellAlignBottom.label;" value="bottom"/>
+                    </menupopup>
+                  </menulist>
+                </row>
+                <row align="center">
+                  <checkbox id="CellHAlignCheckbox" label="&cellHorizontal.label;" accesskey="&cellHorizontal.accessKey;"/>
+                  <menulist id="CellHAlignList"  oncommand="SelectCellHAlign()">
+                    <menupopup>
+                      <menuitem label="&AlignLeft.label;"        value="left"/>
+                      <menuitem label="&AlignCenter.label;"      value="center"/>
+                      <menuitem label="&AlignRight.label;"       value="right"/>
+                      <menuitem label="&cellAlignJustify.label;" value="justify"/>
+                    </menupopup>
+                  </menulist>
+                </row>
+              </rows>
+            </grid>
+          </groupbox>
+        </hbox>
+        <spacer class="spacer"/>
+        <hbox align="center">
+          <checkbox id="CellStyleCheckbox" label="&cellStyle.label;" accesskey="&cellStyle.accessKey;"/>
+          <menulist id="CellStyleList" oncommand="SetCheckbox('CellStyleCheckbox');">
+            <menupopup>
+              <menuitem label="&cellNormal.label;" value="td"/>
+              <menuitem label="&cellHeader.label;" value="th"/>
+            </menupopup>
+          </menulist>
+          <spacer class="bigspacer"/>
+          <checkbox id="TextWrapCheckbox" label="&cellTextWrap.label;" accesskey="&cellTextWrap.accessKey;"/>
+          <menulist id="TextWrapList" oncommand="SetCheckbox('TextWrapCheckbox');">
+            <menupopup>
+              <menuitem label="&cellWrap.label;" value="wrap"/>
+              <menuitem label="&cellNoWrap.label;" value="nowrap"/>
+            </menupopup>
+          </menulist>
+        </hbox>
+        <separator class="groove"/>
+        <hbox align="center">
+          <checkbox id="CellColorCheckbox" label="&backgroundColor.label;" accesskey="&backgroundColor.accessKey;"/>
+          <button class="color-button" oncommand="GetColorAndUpdate('cellBackgroundCW');">
+            <spacer id="cellBackgroundCW" class="color-well"/>
+          </button>
+          <spacer class="spacer"/>
+          <label id="CellInheritColor" value="&cellInheritColor.label;" collapsed="true"/>
+        </hbox>
+        <separator class="groove"/>
+        <hbox align="center">
+          <description class="wrap" flex="1" style="width: 1em">&cellUseCheckboxHelp.label;</description>
+          <!-- From EdDialogOvlerlay.xul -->
+          <button id="AdvancedEditButton2"/>
+        </hbox>
+        <spacer flex="1"/>
+      </vbox><!-- Cell Panel -->
+    </tabpanels> 
+  </tabbox>
+  <spacer class="spacer"/>
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdTextAreaProps.js
@@ -0,0 +1,200 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Text Area Properties Dialog.
+ *
+ * The Initial Developer of the Original Code is
+ * Neil Rashbrook.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s): Neil Rashbrook <neil@parkwaycc.co.uk>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var insertNew;
+var textareaElement;
+
+// dialog initialization code
+
+function Startup()
+{
+  var editor = GetCurrentEditor();
+  if (!editor)
+  {
+    dump("Failed to get active editor!\n");
+    window.close();
+    return;
+  }
+
+  gDialog = {
+    accept:             document.documentElement.getButton("accept"),
+    textareaName:       document.getElementById("TextAreaName"),
+    textareaRows:       document.getElementById("TextAreaRows"),
+    textareaCols:       document.getElementById("TextAreaCols"),
+    textareaWrap:       document.getElementById("TextAreaWrap"),
+    textareaReadOnly:   document.getElementById("TextAreaReadOnly"),
+    textareaDisabled:   document.getElementById("TextAreaDisabled"),
+    textareaTabIndex:   document.getElementById("TextAreaTabIndex"),
+    textareaAccessKey:  document.getElementById("TextAreaAccessKey"),
+    textareaValue:      document.getElementById("TextAreaValue"),
+    MoreSection:        document.getElementById("MoreSection"),
+    MoreFewerButton:    document.getElementById("MoreFewerButton")
+  };
+
+  // Get a single selected text area element
+  const kTagName = "textarea";
+  try {
+    textareaElement = editor.getSelectedElement(kTagName);
+  } catch (e) {}
+
+  if (textareaElement) {
+    // We found an element and don't need to insert one
+    insertNew = false;
+
+    gDialog.textareaValue.value = textareaElement.value;
+  }
+  else
+  {
+    insertNew = true;
+
+    // We don't have an element selected,
+    //  so create one with default attributes
+    try {
+      textareaElement = editor.createElementWithDefaults(kTagName);
+    } catch(e) {}
+
+    if (!textareaElement)
+    {
+      dump("Failed to get selected element or create a new one!\n");
+      window.close();
+      return;
+    }
+    else
+      gDialog.textareaValue.value = GetSelectionAsText();
+  }
+
+  // Make a copy to use for AdvancedEdit
+  globalElement = textareaElement.cloneNode(false);
+
+  InitDialog();
+
+  InitMoreFewer();
+
+  SetTextboxFocus(gDialog.textareaName);
+  
+  SetWindowLocation();
+}
+
+function InitDialog()
+{
+  gDialog.textareaName.value = globalElement.getAttribute("name");
+  gDialog.textareaRows.value = globalElement.getAttribute("rows");
+  gDialog.textareaCols.value = globalElement.getAttribute("cols");
+  gDialog.textareaWrap.value = GetHTMLOrCSSStyleValue(globalElement, "wrap", "white-space");
+  gDialog.textareaReadOnly.checked = globalElement.hasAttribute("readonly");
+  gDialog.textareaDisabled.checked = globalElement.hasAttribute("disabled");
+  gDialog.textareaTabIndex.value = globalElement.getAttribute("tabindex");
+  gDialog.textareaAccessKey.value = globalElement.getAttribute("accesskey");
+  onInput();
+}
+
+function onInput()
+{
+  var disabled = !gDialog.textareaName.value || !gDialog.textareaRows.value || !gDialog.textareaCols.value;
+  if (gDialog.accept.disabled != disabled)
+    gDialog.accept.disabled = disabled;
+}
+
+function ValidateData()
+{
+  var attributes = {
+    name: gDialog.textareaName.value,
+    rows: gDialog.textareaRows.value,
+    cols: gDialog.textareaCols.value,
+    wrap: gDialog.textareaWrap.value,
+    tabindex: gDialog.textareaTabIndex.value,
+    accesskey: gDialog.textareaAccessKey.value
+  };
+  var flags = {
+    readonly: gDialog.textareaReadOnly.checked,
+    disabled: gDialog.textareaDisabled.checked
+  };
+  for (var a in attributes)
+  {
+    if (attributes[a])
+      globalElement.setAttribute(a, attributes[a]);
+    else
+      globalElement.removeAttribute(a);
+  }
+  for (var f in flags)
+  {
+    if (flags[f])
+      globalElement.setAttribute(f, "");
+    else
+      globalElement.removeAttribute(f);
+  }
+  return true;
+}
+
+function onAccept()
+{
+  // All values are valid - copy to actual element in doc or
+  //   element created to insert
+  ValidateData();
+
+  var editor = GetCurrentEditor();
+
+  editor.beginTransaction();
+
+  try {
+    editor.cloneAttributes(textareaElement, globalElement);
+
+    if (insertNew)
+      editor.insertElementAtSelection(textareaElement, true);
+
+    // undoably set value
+    var initialText = gDialog.textareaValue.value;
+    if (initialText != textareaElement.value) {
+      editor.setShouldTxnSetSelection(false);
+
+      while (textareaElement.hasChildNodes())
+        editor.deleteNode(textareaElement.lastChild);
+      if (initialText) {
+        var textNode = editor.document.createTextNode(initialText);
+        editor.insertNode(textNode, textareaElement, 0);
+      }
+
+      editor.setShouldTxnSetSelection(true);
+    }
+  } finally {
+    editor.endTransaction();
+  }
+
+  SaveWindowLocation();
+
+  return true;
+}
+
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EdTextAreaProps.xul
@@ -0,0 +1,135 @@
+<?xml version="1.0"?>
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Text Area Properties Dialog.
+   -
+   - The Initial Developer of the Original Code is
+   - Neil Rashbrook.
+   - Portions created by the Initial Developer are Copyright (C) 2001
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s): Neil Rashbrook <neil@parkwaycc.co.uk>
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either the GNU General Public License Version 2 or later (the "GPL"), or
+   - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the LGPL or the GPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?> 
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorTextAreaProperties.dtd">
+<dialog title="&windowTitle.label;"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        onload="Startup();"
+        buttons="accept,cancel"
+        ondialogaccept="return onAccept();"
+        ondialogcancel="return onCancel();">
+
+  <!-- Methods common to all editor dialogs -->
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdTextAreaProps.js"/>
+
+  <broadcaster id="args" value=""/>
+  <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+  <groupbox><caption label="&Settings.label;"/>
+    <grid><columns><column/><column/></columns>
+      <rows>
+        <row align="center">
+          <label control="TextAreaName" value="&TextAreaName.label;" accesskey="&TextAreaName.accessKey;"/>
+          <textbox id="TextAreaName" oninput="onInput();"/>
+        </row>
+        <row align="center">
+          <label control="TextAreaRows" value="&TextAreaRows.label;" accesskey="&TextAreaRows.accessKey;"/>
+          <hbox>
+            <textbox id="TextAreaRows" class="narrow" oninput="forceInteger(this.id);onInput();"/>
+          </hbox>
+        </row>
+        <row align="center">
+          <label control="TextAreaCols" value="&TextAreaCols.label;" accesskey="&TextAreaCols.accessKey;"/>
+          <hbox>
+            <textbox id="TextAreaCols" class="narrow" oninput="forceInteger(this.id);onInput();"/>
+          </hbox>
+        </row>
+      </rows>
+    </grid>
+    <hbox>
+      <button id="MoreFewerButton" oncommand="onMoreFewer();" persist="more"/>
+    </hbox>
+    <grid id="MoreSection"><columns><column/><column/></columns>
+      <rows>
+        <row align="center">
+          <label control="TextAreaWrap" value="&TextAreaWrap.label;" accesskey="&TextAreaWrap.accessKey;"/>
+          <menulist id="TextAreaWrap">
+            <menupopup>
+              <menuitem label="&WrapDefault.value;"/>
+              <menuitem label="&WrapOff.value;" value="off"/>
+              <menuseparator/>
+              <menuitem label="&WrapSoft.value;" value="soft"/>
+              <menuitem label="&WrapHard.value;" value="hard"/>
+              <menuseparator/>
+              <menuitem label="&WrapPhysical.value;" value="physical"/>
+              <menuitem label="&WrapVirtual.value;" value="virtual"/>
+              <menuseparator/>
+              <menuitem label="normal" value="normal"/>
+              <menuitem label="nowrap" value="nowrap"/>
+              <menuitem label="pre" value="pre"/>
+            </menupopup>
+          </menulist>
+        </row>
+        <row>
+          <spacer/>
+          <checkbox id="TextAreaReadOnly" label="&TextAreaReadOnly.label;" accesskey="&TextAreaReadOnly.accessKey;"/>
+        </row>
+        <row>
+          <spacer/>
+          <checkbox id="TextAreaDisabled" label="&TextAreaDisabled.label;" accesskey="&TextAreaDisabled.accessKey;"/>
+        </row>
+        <row align="center">
+          <label control="TextAreaTabIndex" value="&TextAreaTabIndex.label;" accesskey="&TextAreaTabIndex.accessKey;"/>
+          <hbox>
+            <textbox id="TextAreaTabIndex" class="narrow" oninput="forceInteger(this.id);"/>
+          </hbox>
+        </row>
+        <row align="center">
+          <label control="TextAreaAccessKey" value="&TextAreaAccessKey.label;" accesskey="&TextAreaAccessKey.accessKey;"/>
+          <hbox>
+            <textbox id="TextAreaAccessKey" class="narrow" maxlength="1"/>
+          </hbox>
+        </row>
+        <row>
+          <label control="TextAreaValue" value="&InitialText.label;" accesskey="&InitialText.accessKey;"/>
+        </row>
+        <textbox id="TextAreaValue" flex="1" multiline="true" rows="5"/>
+      </rows>
+    </grid>
+  </groupbox>
+
+  <!-- from EdDialogOverlay -->
+  <vbox id="AdvancedEdit"/>
+
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EditConflict.js
@@ -0,0 +1,72 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// dialog initialization code
+function Startup()
+{
+  if (!GetCurrentEditor())
+  {
+    window.close();
+    return;
+  }
+  
+  SetWindowLocation();
+}
+
+function KeepCurrentPage()
+{
+  // Simply close dialog and don't change current page
+  //TODO: Should we force saving of the current page?
+  SaveWindowLocation();
+  return true;
+}
+
+function UseOtherPage()
+{
+  // Reload the URL -- that will get other editor's contents
+  setTimeout("window.opener.EditorLoadUrl(GetDocumentUrl())", 10);
+  SaveWindowLocation();
+  return true;
+}
+
+function PreventCancel()
+{
+  SaveWindowLocation();
+
+  // Don't let Esc key close the dialog!
+  return false;
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EditConflict.xul
@@ -0,0 +1,76 @@
+<?xml version="1.0"?>
+
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?> 
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditConflict.dtd">
+
+<dialog buttons="cancel" title="&windowTitle.label;"
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    onload = "Startup()"
+    ondialogcancel="return onClose();">
+
+  <!-- Methods common to all editor dialogs -->
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EditConflict.js"/>
+
+  <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+  
+  <label value ="&conflictWarning.label;"/>
+  <spacer class="bigspacer"/>
+  <label value ="&conflictResolve.label;"/>
+  <spacer class="bigspacer"/>
+  <hbox flex="1">
+    <spacer class="bigspacer"/>
+    <button label="&keepCurrentPageButton.label;"
+            oncommand="KeepCurrentPage()"/>
+    <spacer class="bigspacer"/>
+  </hbox>
+  <hbox flex="1">
+    <spacer class="bigspacer"/>
+    <button dlgtype="cancel"
+            label="&useOtherPageButton.label;"
+            oncommand="UseOtherPage()"/>
+    <spacer class="bigspacer"/>
+  </hbox>
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EditorPublish.js
@@ -0,0 +1,589 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Charley Manske (cmanske@netscape.com)
+ *   Ryan Cassin (rcassin@supernova.org)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var gPublishSiteData;
+var gReturnData;
+var gDefaultSiteIndex = -1;
+var gDefaultSiteName;
+var gPreviousDefaultDir;
+var gPreviousTitle;
+var gSettingsChanged = false;
+var gInitialSiteName;
+var gInitialSiteIndex = -1;
+var gPasswordManagerOn = true;
+
+// Dialog initialization code
+function Startup()
+{
+  window.opener.ok = false;
+
+  // Element to edit is passed in
+  gInitialSiteName = window.arguments[1];
+  gReturnData = window.arguments[2];
+  if (!gReturnData || !GetCurrentEditor())
+  {
+    dump("Publish: No editor or return data object not supplied\n");
+    window.close();
+    return;
+  }
+
+  gDialog.TabBox              = document.getElementById("TabBox");
+  gDialog.PublishTab          = document.getElementById("PublishTab");
+  gDialog.SettingsTab         = document.getElementById("SettingsTab");
+
+  // Publish panel
+  gDialog.PageTitleInput      = document.getElementById("PageTitleInput");
+  gDialog.FilenameInput       = document.getElementById("FilenameInput");
+  gDialog.SiteList            = document.getElementById("SiteList");
+  gDialog.DocDirList          = document.getElementById("DocDirList");
+  gDialog.OtherDirCheckbox    = document.getElementById("OtherDirCheckbox");
+  gDialog.OtherDirRadiogroup  = document.getElementById("OtherDirRadiogroup");
+  gDialog.SameLocationRadio   = document.getElementById("SameLocationRadio");
+  gDialog.UseSubdirRadio      = document.getElementById("UseSubdirRadio");
+  gDialog.OtherDirList        = document.getElementById("OtherDirList");
+
+  // Settings Panel
+  gDialog.SiteNameInput       = document.getElementById("SiteNameInput");
+  gDialog.PublishUrlInput     = document.getElementById("PublishUrlInput");
+  gDialog.BrowseUrlInput      = document.getElementById("BrowseUrlInput");
+  gDialog.UsernameInput       = document.getElementById("UsernameInput");
+  gDialog.PasswordInput       = document.getElementById("PasswordInput");
+  gDialog.SavePassword        = document.getElementById("SavePassword");
+
+  gPasswordManagerOn = GetBoolPref("signon.rememberSignons");
+  gDialog.SavePassword.disabled = !gPasswordManagerOn;
+
+  gPublishSiteData = GetPublishSiteData();
+  gDefaultSiteName = GetDefaultPublishSiteName();
+
+  var addNewSite = false;
+  if (gPublishSiteData)
+  {
+    FillSiteList();
+  }
+  else
+  {
+    // No current site data, start a new item in the Settings panel
+    AddNewSite();
+    addNewSite = true;
+  }
+
+  var docUrl = GetDocumentUrl();
+  var scheme = GetScheme(docUrl);
+  var filename = "";
+
+  if (scheme)
+  {
+    filename = GetFilename(docUrl);
+
+    if (scheme != "file")
+    {
+      var siteFound = false;
+
+      // Editing a remote URL.
+      // Attempt to find doc URL in Site Data
+      if (gPublishSiteData)
+      {
+        var dirObj = {};
+        var siteIndex = FindSiteIndexAndDocDir(gPublishSiteData, docUrl, dirObj);
+
+        // Select this site only if the same as user's intended site, or there wasn't one
+        if (siteIndex != -1 && (gInitialSiteIndex == -1 || siteIndex == gInitialSiteIndex))
+        {
+          siteFound = true;
+
+          // Select the site we found
+          gDialog.SiteList.selectedIndex = siteIndex;
+          var docDir = dirObj.value;
+
+          // Use the directory within site in the editable menulist
+          gPublishSiteData[siteIndex].docDir = docDir;
+
+          //XXX HOW DO WE DECIDE WHAT "OTHER" DIR TO USE?
+          //gPublishSiteData[siteIndex].otherDir = docDir;
+        }
+      }
+      if (!siteFound)
+      {
+        // Not found in site database 
+        // Setup for a new site and use data from a remote URL
+        if (!addNewSite)
+          AddNewSite();
+
+        addNewSite = true;
+
+        var publishData = CreatePublishDataFromUrl(docUrl);
+        if (publishData)
+        {
+          filename = publishData.filename;
+          gDialog.SiteNameInput.value    = publishData.siteName;
+          gDialog.PublishUrlInput.value  = publishData.publishUrl;
+          gDialog.BrowseUrlInput.value   = publishData.browseUrl;
+          gDialog.UsernameInput.value    = publishData.username;
+          gDialog.PasswordInput.value    = publishData.password;
+          gDialog.SavePassword.checked   = false;
+        }
+      }
+    }
+  }
+  try {
+    gPreviousTitle = GetDocumentTitle();
+  } catch (e) {}
+
+  gDialog.PageTitleInput.value = gPreviousTitle;
+  gDialog.FilenameInput.value = decodeURIComponent(filename);
+  
+  if (!addNewSite)
+  {
+    // If not adding a site and we haven't selected a site -- use initial or default site
+    if (gDialog.SiteList.selectedIndex == -1)
+      gDialog.SiteList.selectedIndex = (gInitialSiteIndex != -1) ? gInitialSiteIndex : gDefaultSiteIndex;
+
+    // Fill in  all the site data for currently-selected site
+    SelectSiteList();
+    SetTextboxFocus(gDialog.PageTitleInput);
+  }
+
+  if (gDialog.SiteList.selectedIndex == -1)
+  {
+    // No selected site -- assume same directory
+    gDialog.OtherDirRadiogroup.selectedItem = gDialog.SameLocationRadio;
+  }
+  else if (gPublishSiteData[gDialog.SiteList.selectedIndex].docDir == 
+        gPublishSiteData[gDialog.SiteList.selectedIndex].otherDir)
+  {
+    // For now, check "same location" if dirs are already set to same directory
+    gDialog.OtherDirRadiogroup.selectedItem = gDialog.SameLocationRadio;
+  }
+  else
+  {
+    gDialog.OtherDirRadiogroup.selectedItem = gDialog.UseSubdirRadio;
+  }
+
+  doEnabling();
+
+  SetWindowLocation();
+}
+
+function FillSiteList()
+{
+  gDialog.SiteList.removeAllItems();
+  gDefaultSiteIndex = -1;
+
+  // Fill the site lists
+  var count = gPublishSiteData.length;
+  var i;
+
+  for (i = 0; i < count; i++)
+  {
+    var name = gPublishSiteData[i].siteName;
+    var menuitem = gDialog.SiteList.appendItem(name);
+    // Highlight the default site
+    if (name == gDefaultSiteName)
+    {
+      gDefaultSiteIndex = i;
+      if (menuitem)
+      {
+        menuitem.setAttribute("class", "menuitem-highlight-1");
+        menuitem.setAttribute("default", "true");
+      }
+    }
+    // Find initial site location
+    if (name == gInitialSiteName)
+      gInitialSiteIndex = i;
+  }
+}
+
+function doEnabling()
+{
+  var disableOther = !gDialog.OtherDirCheckbox.checked;
+  gDialog.SameLocationRadio.disabled = disableOther;
+  gDialog.UseSubdirRadio.disabled = disableOther;
+  gDialog.OtherDirList.disabled = (disableOther || gDialog.SameLocationRadio.selected);
+}
+
+function SelectSiteList()
+{
+  var selectedSiteIndex = gDialog.SiteList.selectedIndex;  
+
+  var siteName = "";
+  var publishUrl = "";
+  var browseUrl = "";
+  var username = "";
+  var password = "";
+  var savePassword = false;
+  var publishOtherFiles = true;
+
+  gDialog.DocDirList.removeAllItems();
+  gDialog.OtherDirList.removeAllItems();
+
+  if (gPublishSiteData && selectedSiteIndex != -1)
+  {
+    siteName = gPublishSiteData[selectedSiteIndex].siteName;
+    publishUrl = gPublishSiteData[selectedSiteIndex].publishUrl;
+    browseUrl = gPublishSiteData[selectedSiteIndex].browseUrl;
+    username = gPublishSiteData[selectedSiteIndex].username;
+    savePassword = gPasswordManagerOn ? gPublishSiteData[selectedSiteIndex].savePassword : false;
+    if (savePassword)
+      password = gPublishSiteData[selectedSiteIndex].password;
+
+    // Fill the directory menulists
+    if (gPublishSiteData[selectedSiteIndex].dirList.length)
+    {
+      for (var i = 0; i < gPublishSiteData[selectedSiteIndex].dirList.length; i++)
+      {
+        gDialog.DocDirList.appendItem(gPublishSiteData[selectedSiteIndex].dirList[i]);
+        gDialog.OtherDirList.appendItem(gPublishSiteData[selectedSiteIndex].dirList[i]);
+      }
+    }
+    gDialog.DocDirList.value = FormatDirForPublishing(gPublishSiteData[selectedSiteIndex].docDir);
+    gDialog.OtherDirList.value = FormatDirForPublishing(gPublishSiteData[selectedSiteIndex].otherDir);
+    publishOtherFiles = gPublishSiteData[selectedSiteIndex].publishOtherFiles;
+
+  }
+  else
+  {
+    gDialog.DocDirList.value = "";
+    gDialog.OtherDirList.value = "";
+  }
+
+  gDialog.SiteNameInput.value    = siteName;
+  gDialog.PublishUrlInput.value  = publishUrl;
+  gDialog.BrowseUrlInput.value   = browseUrl;
+  gDialog.UsernameInput.value    = username;
+  gDialog.PasswordInput.value    = password;
+  gDialog.SavePassword.checked   = savePassword;
+  gDialog.OtherDirCheckbox.checked = publishOtherFiles;
+
+  doEnabling();
+}
+
+function AddNewSite()
+{
+  // Button in Publish panel allows user
+  //  to automatically switch to "Settings" panel
+  //  to enter data for new site
+  SwitchPanel(gDialog.SettingsTab);
+  
+  gDialog.SiteList.selectedIndex = -1;
+
+  SelectSiteList();
+  
+  gSettingsChanged = true;
+
+  SetTextboxFocus(gDialog.SiteNameInput);
+}
+
+function SelectPublishTab()
+{
+  if (gSettingsChanged && !ValidateSettings())
+    return;
+
+  SwitchPanel(gDialog.PublishTab);
+  SetTextboxFocus(gDialog.PageTitleInput);
+}
+
+function SelectSettingsTab()
+{
+  SwitchPanel(gDialog.SettingsTab);
+  SetTextboxFocus(gDialog.SiteNameInput);
+}
+
+function SwitchPanel(tab)
+{
+  if (gDialog.TabBox.selectedTab != tab)
+    gDialog.TabBox.selectedTab = tab;
+}
+
+function onInputSettings()
+{
+  // TODO: Save current data during SelectSite and compare here
+  //       to detect if real change has occured?
+  gSettingsChanged = true;
+}
+
+function GetPublishUrlInput()
+{
+  gDialog.PublishUrlInput.value = FormatUrlForPublishing(gDialog.PublishUrlInput.value);
+  return gDialog.PublishUrlInput.value;
+}
+
+function GetBrowseUrlInput()
+{
+  gDialog.BrowseUrlInput.value = FormatUrlForPublishing(gDialog.BrowseUrlInput.value);
+  return gDialog.BrowseUrlInput.value;
+}
+
+function GetDocDirInput()
+{
+  gDialog.DocDirList.value = FormatDirForPublishing(gDialog.DocDirList.value);
+  return gDialog.DocDirList.value;
+}
+
+function GetOtherDirInput()
+{
+  gDialog.OtherDirList.value = FormatDirForPublishing(gDialog.OtherDirList.value);
+  return gDialog.OtherDirList.value;
+}
+
+function ChooseDir(menulist)
+{
+  //TODO: For FTP publish destinations, get file listing of just dirs 
+  //  and build a tree to let user select dir
+}
+
+function ValidateSettings()
+{
+  var siteName = TrimString(gDialog.SiteNameInput.value);
+  if (!siteName)
+  {
+    ShowErrorInPanel(gDialog.SettingsTab, "MissingSiteNameError", gDialog.SiteNameInput);
+    return false;
+  }
+  if (PublishSiteNameExists(siteName, gPublishSiteData, gDialog.SiteList.selectedIndex))
+  {
+    SwitchPanel(gDialog.SettingsTab);
+    ShowInputErrorMessage(GetString("DuplicateSiteNameError").replace(/%name%/, siteName));            
+    SetTextboxFocus(gDialog.SiteNameInput);
+    return false;
+  }
+
+  // Extract username and password while removing them from publishingUrl
+  var urlUserObj = {};
+  var urlPassObj = {};
+  var publishUrl = StripUsernamePassword(gDialog.PublishUrlInput.value, urlUserObj, urlPassObj);
+  if (publishUrl)
+  {
+    publishUrl = FormatUrlForPublishing(publishUrl);
+
+    // Assume scheme = "ftp://" if missing
+    // This compensates when user enters hostname w/o scheme (as most ISPs provide)
+    if (!GetScheme(publishUrl))
+      publishUrl = "ftp://" + publishUrl; 
+
+    gDialog.PublishUrlInput.value = publishUrl;
+  }
+  else
+  {
+    ShowErrorInPanel(gDialog.SettingsTab, "MissingPublishUrlError", gDialog.PublishUrlInput);
+    return false;
+  }
+  var browseUrl = GetBrowseUrlInput();
+
+  var username = TrimString(gDialog.UsernameInput.value);
+  var savePassword = gDialog.SavePassword.checked;
+  var password = gDialog.PasswordInput.value;
+  var publishOtherFiles = gDialog.OtherDirCheckbox.checked;
+  
+  //XXX If there was a username and/or password in the publishUrl 
+  //    AND in the input field, which do we use?
+  //    Let's use those in url only if input is empty 
+  if (!username)
+  {
+    username = urlUserObj.value;
+    gDialog.UsernameInput.value = username;
+    gSettingsChanged = true;
+  }
+  if (!password)
+  {
+    password = urlPassObj.value;
+    gDialog.PasswordInput.value = password;
+    gSettingsChanged = true;
+  }
+
+  // Update or add data for a site 
+  var siteIndex = gDialog.SiteList.selectedIndex;
+  var newSite = false;
+
+  if (siteIndex == -1)
+  {
+    // No site is selected, add a new site at the end
+    if (gPublishSiteData)
+    {
+      siteIndex = gPublishSiteData.length;
+    }
+    else
+    {
+      // First time: start entire site array
+      gPublishSiteData = new Array(1);
+      siteIndex = 0;
+      gDefaultSiteIndex = 0;
+      gDefaultSiteName = siteName;
+    }    
+    gPublishSiteData[siteIndex] = {};
+    gPublishSiteData[siteIndex].docDir = "";
+    gPublishSiteData[siteIndex].otherDir = "";
+    gPublishSiteData[siteIndex].dirList = [""];
+    gPublishSiteData[siteIndex].publishOtherFiles = true;
+    gPublishSiteData[siteIndex].previousSiteName = siteName;
+    newSite = true;
+  }
+  gPublishSiteData[siteIndex].siteName = siteName;
+  gPublishSiteData[siteIndex].publishUrl = publishUrl;
+  gPublishSiteData[siteIndex].browseUrl = browseUrl;
+  gPublishSiteData[siteIndex].username = username;
+  // Don't save password in data that will be saved in prefs
+  gPublishSiteData[siteIndex].password = savePassword ? password : "";
+  gPublishSiteData[siteIndex].savePassword = savePassword;
+
+  if (publishOtherFiles != gPublishSiteData[siteIndex].publishOtherFiles)
+    gSettingsChanged = true;
+
+  gPublishSiteData[siteIndex].publishOtherFiles = publishOtherFiles;
+
+  gDialog.SiteList.selectedIndex = siteIndex;
+  if (siteIndex == gDefaultSiteIndex)
+    gDefaultSiteName = siteName;
+
+  // Should never be empty, but be sure we have a default site
+  if (!gDefaultSiteName)
+  {
+    gDefaultSiteName = gPublishSiteData[0].siteName;
+    gDefaultSiteIndex = 0;
+  }
+
+  // Rebuild the site menulist if we added a new site
+  if (newSite)
+  {
+    FillSiteList();
+    gDialog.SiteList.selectedIndex = siteIndex;
+  }
+  else
+  {
+    // Update selected item if sitename changed 
+    var selectedItem = gDialog.SiteList.selectedItem;
+    if (selectedItem)
+    {
+      var oldName = selectedItem.getAttribute("label");
+      if (oldName != siteName)
+      {
+        selectedItem.setAttribute("label", siteName);
+        gDialog.SiteList.setAttribute("label", siteName);
+        gSettingsChanged = true;
+        if (oldName == gDefaultSiteName)
+          gDefaultSiteName = siteName;
+      }
+    }
+  }
+  
+  // Get the directory name in site to publish to
+  var docDir = GetDocDirInput();
+
+  gPublishSiteData[siteIndex].docDir = docDir;
+
+  // And directory for images and other files
+  var otherDir = GetOtherDirInput();
+  if (gDialog.SameLocationRadio.selected)
+    otherDir = docDir;
+  else
+    otherDir = GetOtherDirInput();
+
+  gPublishSiteData[siteIndex].otherDir = otherDir;
+
+  // Fill return data object
+  gReturnData.siteName = siteName;
+  gReturnData.previousSiteName = gPublishSiteData[siteIndex].previousSiteName;
+  gReturnData.publishUrl = publishUrl;
+  gReturnData.browseUrl = browseUrl;
+  gReturnData.username = username;
+  // Note that we use the password for the next publish action 
+  // even if savePassword is false; but we won't save it in PasswordManager database
+  gReturnData.password = password;
+  gReturnData.savePassword = savePassword;
+  gReturnData.docDir = gPublishSiteData[siteIndex].docDir;
+  gReturnData.otherDir = gPublishSiteData[siteIndex].otherDir;
+  gReturnData.publishOtherFiles = publishOtherFiles;
+  gReturnData.dirList = gPublishSiteData[siteIndex].dirList;
+  return true;
+}
+
+function ValidateData()
+{
+  if (!ValidateSettings())
+    return false;
+
+  var siteIndex = gDialog.SiteList.selectedIndex;
+  if (siteIndex == -1)
+    return false;
+
+  var filename = TrimString(gDialog.FilenameInput.value);
+  if (!filename)
+  {
+    ShowErrorInPanel(gDialog.PublishTab, "MissingPublishFilename", gDialog.FilenameInput);
+    return false;
+  }
+  gReturnData.filename = filename;
+
+  return true;
+}
+
+function ShowErrorInPanel(tab, errorMsgId, widgetWithError)
+{
+  SwitchPanel(tab);
+  ShowInputErrorMessage(GetString(errorMsgId));
+  if (widgetWithError)
+    SetTextboxFocus(widgetWithError);
+}
+
+function onAccept()
+{
+  if (ValidateData())
+  {
+    //  DON'T save the docDir and otherDir before trying to publish
+    gReturnData.saveDirs = false;
+
+    // We save new site data to prefs only if we are attempting to publish
+    if (gSettingsChanged)
+      SavePublishDataToPrefs(gReturnData);
+
+    // Set flag to resave data after publishing
+    // so we save docDir and otherDir if we published successfully
+    gReturnData.savePublishData = true;
+
+    var title = TrimString(gDialog.PageTitleInput.value);
+    if (title != gPreviousTitle)
+      SetDocumentTitle(title);
+
+    SaveWindowLocation();
+    window.opener.ok = true;
+    return true;
+  }
+
+  return false;
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EditorPublish.xul
@@ -0,0 +1,160 @@
+<?xml version="1.0"?>
+
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 2001
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?> 
+<?xul-overlay href="chrome://editor/content/EditorPublishOverlay.xul"?> 
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorPublish.dtd">
+
+<dialog title="&windowTitle.label;"
+        id="publishDlg"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        onload="Startup()"
+        buttons="accept,cancel"
+        buttonlabelaccept="&publishButton.label;"
+        ondialogaccept="return onAccept();"
+        ondialogcancel="return onCancel();">
+
+  <!-- Methods common to all editor dialogs -->
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EditorPublish.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/publishprefs.js"/>
+
+  <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+  <broadcaster id="args" value=""/>
+
+  <tabbox id="TabBox">
+    <tabs flex="1">
+      <tab id="PublishTab" oncommand="SelectPublishTab()" label="&publishTab.label;"/>
+      <tab id="SettingsTab" oncommand="SelectSettingsTab()" label="&settingsTab.label;"/>
+    </tabs>
+    <tabpanels>
+      <!-- PUBLISH PANEL -->
+      <vbox>
+        <spacer class="spacer"/>
+        <grid pack="start">
+          <columns><column/><column/><column/></columns>
+          <rows>
+            <row align="center">
+              <label value="&siteList.label;"/>
+              <!-- Contents filled in at runtime -->
+              <menulist id="SiteList" 
+                style="min-width:18em; max-width:18em;" crop="right"
+                oncommand="SelectSiteList();"/>
+              <hbox>
+                <button label="&newSiteButton.label;"
+                        accesskey="&newSiteButton.accesskey;"
+                        oncommand="AddNewSite();"/>
+                <spacer flex="1"/>
+              </hbox>
+            </row>
+            <spacer class="spacer"/>
+            <row align="center">
+              <label value="&pageTitle.label;" accesskey="&pageTitle.accesskey;"
+                     control="PageTitleInput"/>
+              <textbox id="PageTitleInput" 
+                tooltiptext="&pageTitle.tooltip;" class="minWidth15"/>
+              <label value="&pageTitleExample.label;"/>
+            </row>
+            <row align="center">
+              <label value="&filename.label;" accesskey="&filename.accesskey;"
+                     control="FilenameInput"/>
+              <textbox id="FilenameInput"
+                tooltiptext="&filename.tooltip;" class="minWidth15 uri-element"/>
+              <label value="&filenameExample.label;"/>
+            </row>
+          </rows>
+        </grid>
+        <spacer class="spacer"/>
+        <label value="&docDirList.label;"/>
+        <hbox align="center">
+          <!-- Contents filled in at runtime -->
+          <menulist id="DocDirList" class="minWidth20 uri-element" editable="true"  flex="1"
+                    tooltiptext="&docDirList.tooltip;" oninput="onInputSettings();"/>
+        </hbox>
+        <spacer class="spacer"/>
+        <groupbox>
+          <caption>
+            <checkbox id="OtherDirCheckbox" label="&publishImgCheckbox.label;" 
+                      accesskey="&publishImgCheckbox.accesskey;"
+                      tooltiptext="&publishImgCheckbox.tooltip;"
+                      oncommand="doEnabling();"/>
+          </caption>
+          <vbox>
+          <radiogroup id="OtherDirRadiogroup">
+            <hbox>
+              <spacer class="checkbox-spacer"/>
+              <radio id="SameLocationRadio" label="&sameLocationRadio.label;"
+                     accesskey="&sameLocationRadio.accesskey;"
+                     tooltiptext="&sameLocationRadio.tooltip;"
+                     oncommand="doEnabling();"/>
+            </hbox>
+            <hbox>
+              <spacer class="checkbox-spacer"/>
+              <radio id="UseSubdirRadio" label="&useSubdirRadio.label;"
+                     accesskey="&useSubdirRadio.accesskey;"
+                     tooltiptext="&useSubdirRadio.tooltip;"
+                     oncommand="doEnabling();"/>
+            </hbox>
+          </radiogroup>
+          </vbox>
+          <hbox>
+            <spacer class="checkbox-spacer"/>
+            <spacer class="radio-spacer"/>
+            <!-- Contents filled in at runtime -->
+            <menulist id="OtherDirList" class="minWidth20 uri-element"
+                      editable="true" flex="1" tooltiptext="&otherDirList.tooltip;"
+                      oninput="onInputSettings();"/>
+          </hbox>
+        </groupbox>
+        <spacer flex="1"/>
+      </vbox><!-- Publish Panel -->
+
+      <!-- SETTINGS PANEL -->
+      <hbox id="SettingsPanel">
+        <!-- from EditorPublishOverlay.xul -->
+        <vbox id="PublishSettingsInputs" flex="1"/>
+      </hbox><!-- Settings Panel -->
+    </tabpanels> 
+  </tabbox>
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EditorPublishOverlay.xul
@@ -0,0 +1,98 @@
+<?xml version="1.0"?>
+
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 2001
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!DOCTYPE overlay SYSTEM "chrome://editor/locale/EditorPublish.dtd">
+
+<overlay id="EditorPublishOverlay"
+     xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+<vbox id="PublishSettingsInputs">
+  <groupbox id="ServerSettingsBox">
+    <caption label="&serverInfo.label;"/>
+    <hbox align="center">
+      <label value="&siteName.label;" accesskey="&siteName.accesskey;"
+             control="SiteNameInput"/>
+      <textbox id="SiteNameInput" class="MinWidth20em" flex="1"
+               tooltiptext="&siteName.tooltip;" oninput="onInputSettings();"/>
+    </hbox>
+    <spacer class="spacer"/>
+    <label value="&siteUrl.label;" accesskey="&siteUrl.accesskey;"
+           control="PublishUrlInput"/>
+    <textbox id="PublishUrlInput" class="MinWidth20em uri-element"
+             tooltiptext="&siteUrl.tooltip;" oninput="onInputSettings();"/>
+    <spacer class="spacer"/>
+    <label value="&browseUrl.label;" accesskey="&browseUrl.accesskey;"
+           control="BrowseUrlInput"/>
+    <textbox id="BrowseUrlInput" class="MinWidth20em uri-element" 
+             tooltiptext="&browseUrl.tooltip;" oninput="onInputSettings();"/>
+    <spacer class="spacer"/>
+  </groupbox>
+  <groupbox id="LoginSettingsBox">
+    <caption label="&loginInfo.label;"/>
+    <grid>
+      <columns><column flex="1"/><column flex="3"/></columns>
+      <rows>
+        <row align="center">
+          <label value="&username.label;" accesskey="&username.accesskey;"
+                 control="UsernameInput"/>
+          <textbox id="UsernameInput" class="MinWidth10em" flex="1"
+                   tooltiptext="&username.tooltip;" oninput="onInputSettings();"/>
+        </row>
+        <row align="center">
+          <label value="&password.label;" accesskey="&password.accesskey;"
+                 control="PasswordInput"/>
+          <hbox>
+            <textbox id="PasswordInput" type="password" class="MinWidth5em" 
+                     oninput="onInputSettings();"/>
+            <checkbox id="SavePassword" label="&savePassword.label;"
+                      accesskey="&savePassword.accesskey;" 
+                      tooltiptext="&savePassword.tooltip;"
+                      oncommand="onInputSettings();"/>
+          </hbox>
+        </row>
+      </rows>
+    </grid>
+    <spacer class="spacer"/>
+  </groupbox>
+</vbox>
+
+</overlay>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EditorPublishProgress.js
@@ -0,0 +1,435 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Charles Manske (cmanske@netscape.com)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var gInProgress = true;
+var gPublishData;
+var gPersistObj;
+var gTotalFileCount = 0;
+var gSucceededCount = 0;
+var gFinished = false;
+var gPublishingFailed = false;
+var gFileNotFound = false;
+var gStatusMessage="";
+
+var gTimerID;
+var gAllowEnterKey = false;
+
+// Publishing error codes
+//   These are translated from C++ error code strings like this:
+//   kFileNotFound = "FILE_NOT_FOUND",
+const kNetReset = 2152398868; // nsISocketTransportService.idl
+const kFileNotFound = 2152857618;
+const kNotConnected = 2152398860; // in netCore.h
+const kConnectionRefused = 2152398861; // nsISocketTransportService.idl
+const kNetTimeout = 2152398862; // nsISocketTransportService.idl
+const kNoConnectionOrTimeout = 2152398878;
+const kPortAccessNotAllowed = 2152398867; // netCore.h
+const kOffline = 2152398865; // netCore.h
+const kDiskFull = 2152857610;
+const kNoDeviceSpace = 2152857616;
+const kNameTooLong = 2152857617;
+const kAccessDenied = 2152857621;
+
+// These are more errors that I don't think we encounter during publishing,
+//  so we don't have error strings yet. Let's keep them here for future reference
+//const kUnrecognizedPath = 2152857601;
+//const kUnresolvableSymlink = 2152857602;
+//const kUnknownType = 2152857604;
+//const kDestinationNotDir = 2152857605;
+//const kTargetDoesNotExist = 2152857606;
+//const kAlreadyExists = 2152857608;
+//const kInvalidPath = 2152857609;
+//const kNotDirectory = 2152857612;
+//const kIsDirectory = 2152857613;
+//const kIsLocked = 2152857614;
+//const kTooBig = 2152857615;
+//const kReadOnly = 2152857619;
+//const kDirectoryNotEmpty = 2152857620;
+//const kErrorBindingRedirected = 2152398851;
+//const kAlreadyConnected = 2152398859; // in netCore.h
+//const kInProgress = 2152398863; // netCore.h
+//const kNoContent = 2152398865; // netCore.h
+//const kUnknownProtocol = 2152398866 // netCore.h
+//const kFtpLogin = 2152398869; // ftpCore.h
+//const kFtpCWD = 2152398870; // ftpCore.h
+//const kFtpPasv = 2152398871; // ftpCore.h
+//const kFtpPwd = 2152398872; // ftpCore.h
+
+
+function Startup()
+{
+  gPublishData = window.arguments[0];
+  if (!gPublishData)
+  {
+    dump("No publish data!\n");
+    window.close();
+    return;
+  }
+
+  gDialog.FileList           = document.getElementById("FileList");
+  gDialog.FinalStatusMessage = document.getElementById("FinalStatusMessage");
+  gDialog.StatusMessage      = document.getElementById("StatusMessage");
+  gDialog.KeepOpen           = document.getElementById("KeepOpen");
+  gDialog.Close              = document.documentElement.getButton("cancel");
+
+  SetWindowLocation();
+  var title = GetDocumentTitle();
+  if (!title)
+    title = "("+GetString("untitled")+")";
+  document.title = GetString("PublishProgressCaption").replace(/%title%/, title);
+
+  document.getElementById("PublishToSite").value = 
+    GetString("PublishToSite").replace(/%title%/, TruncateStringAtWordEnd(gPublishData.siteName, 25)); 
+
+  // Show publishing destination URL
+  document.getElementById("PublishUrl").value = gPublishData.publishUrl;
+  
+  // Show subdirectories only if not empty
+  if (gPublishData.docDir || gPublishData.otherDir)
+  {
+    if (gPublishData.docDir)
+      document.getElementById("docDir").value = gPublishData.docDir;
+    else
+      document.getElementById("DocSubdir").hidden = true;
+      
+    if (gPublishData.publishOtherFiles && gPublishData.otherDir)
+      document.getElementById("otherDir").value = gPublishData.otherDir;
+    else
+      document.getElementById("OtherSubdir").hidden = true;
+  }
+  else
+    document.getElementById("Subdirectories").hidden = true;
+
+  // Add the document to the "publish to" list as quick as possible!
+  SetProgressStatus(gPublishData.filename, "busy");
+
+  if (gPublishData.publishOtherFiles)
+  {
+    // When publishing images as well, expand list to show more items
+    gDialog.FileList.setAttribute("rows", 5);
+    window.sizeToContent();
+  }
+
+  // Now that dialog is initialized, we can start publishing
+  gPersistObj = window.opener.StartPublishing();
+}
+
+// this function is to be used when we cancel persist's saving
+// since not all messages will be returned to us if we cancel
+// this function changes status for all non-done/non-failure to failure
+function SetProgressStatusCancel()
+{
+  var listitems = document.getElementsByTagName("listitem");
+  if (!listitems)
+    return;
+
+  for (var i=0; i < listitems.length; i++)
+  {
+    var attr = listitems[i].getAttribute("progress");
+    if (attr != "done" && attr != "failed")
+      listitems[i].setAttribute("progress", "failed");
+  }
+}
+
+// Add filename to list of files to publish
+// or set status for file already in the list
+// Returns true if file was in the list
+function SetProgressStatus(filename, status)
+{
+  if (!filename)
+    return false;
+
+  if (!status)
+    status = "busy";
+
+  // Just set attribute for status icon 
+  // if we already have this filename 
+  var listitems = document.getElementsByTagName("listitem");
+  if (listitems)
+  {
+    for (var i=0; i < listitems.length; i++)
+    {
+      if (listitems[i].getAttribute("label") == filename)
+      {
+        listitems[i].setAttribute("progress", status);
+        return true;
+      }
+    }
+  }
+  // We're adding a new file item to list
+  gTotalFileCount++;
+
+  var listitem = document.createElementNS(XUL_NS, "listitem");
+  if (listitem)
+  {
+    listitem.setAttribute("class", "listitem-iconic progressitem");
+    // This triggers CSS to show icon for each status state
+    listitem.setAttribute("progress", status);
+    listitem.setAttribute("label", filename);
+    gDialog.FileList.appendChild(listitem);
+  }
+  return false;
+}
+
+function SetProgressFinished(filename, networkStatus)
+{
+  var abortPublishing = false;
+  if (filename)
+  {
+    var status = networkStatus ? "failed" : "done";
+    if (networkStatus == 0)
+      gSucceededCount++;
+
+    SetProgressStatus(filename, status);
+  }
+
+  if (networkStatus != 0) // Error condition
+  {
+    // We abort on all errors except if image file was not found
+    abortPublishing = networkStatus != kFileNotFound;
+
+    // Mark all remaining files as "failed"
+    if (abortPublishing)
+    {
+      gPublishingFailed = true;
+      SetProgressStatusCancel();
+      gDialog.FinalStatusMessage.value = GetString("PublishFailed");
+    }
+
+    switch (networkStatus)
+    {
+      case kFileNotFound:
+        gFileNotFound = true;
+        if (filename)
+          gStatusMessage = GetString("FileNotFound").replace(/%file%/, filename);
+        break;
+      case kNetReset:
+        // We get this when subdir doesn't exist AND
+        //   if filename used is same as an existing subdir 
+        var dir = (gPublishData.filename == filename) ? 
+                     gPublishData.docDir : gPublishData.otherDir;
+
+        if (dir)
+        {
+          // This is the ambiguous case when we can't tell if subdir or filename is bad
+          // Remove terminal "/" from dir string and insert into message
+          gStatusMessage = GetString("SubdirDoesNotExist").replace(/%dir%/, dir.slice(0, dir.length-1));
+          gStatusMessage = gStatusMessage.replace(/%file%/, filename);
+
+          // Remove directory from saved prefs
+          // XXX Note that if subdir is good, 
+          //     but filename = next level subdirectory name, 
+          //     we really shouldn't remove subdirectory, 
+          //     but it's impossible to differentiate this case!
+          RemovePublishSubdirectoryFromPrefs(gPublishData, dir);
+        }
+        else if (filename)
+          gStatusMessage = GetString("FilenameIsSubdir").replace(/%file%/, filename);
+
+        break;
+      case kNotConnected:
+      case kConnectionRefused:
+      case kNetTimeout:
+      case kNoConnectionOrTimeout:
+      case kPortAccessNotAllowed:
+        gStatusMessage = GetString("ServerNotAvailable");
+        break;
+      case kOffline:
+        gStatusMessage = GetString("Offline");
+        break;
+      case kDiskFull:
+      case kNoDeviceSpace:
+        if (filename)
+          gStatusMessage = GetString("DiskFull").replace(/%file%/, filename);
+        break;
+      case kNameTooLong:
+        if (filename)
+          gStatusMessage = GetString("NameTooLong").replace(/%file%/, filename);
+        break;
+      case kAccessDenied:
+        if (filename)
+          gStatusMessage = GetString("AccessDenied").replace(/%file%/, filename);
+        break;
+      case kUnknownType:
+      default:
+        gStatusMessage = GetString("UnknownPublishError")
+        break;
+    }
+  }
+  else if (!filename)
+  {
+    gFinished = true;
+
+    document.documentElement.setAttribute("buttonlabelcancel",
+      document.documentElement.getAttribute("buttonlabelclose"));
+
+    if (!gStatusMessage)
+      gStatusMessage = GetString(gPublishingFailed ? "UnknownPublishError" : "AllFilesPublished");
+
+    // Now allow "Enter/Return" key to close the dialog
+    AllowDefaultButton();
+
+    if (gPublishingFailed || gFileNotFound)
+    {
+      // Show "Troubleshooting" button to help solving problems
+      //  and key for successful / failed files
+      document.getElementById("failureBox").hidden = false;
+    }
+  }
+
+  if (gStatusMessage)
+    SetStatusMessage(gStatusMessage);
+}
+
+function CheckKeepOpen()
+{
+  if (gTimerID)
+  {
+    clearTimeout(gTimerID);
+    gTimerID = null;
+  }
+}
+
+function onClose()
+{
+  if (!gFinished)
+  {
+    const nsIPromptService = Components.interfaces.nsIPromptService;
+    var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
+                                  .getService(nsIPromptService);
+    const buttonFlags = (nsIPromptService.BUTTON_TITLE_IS_STRING *
+                         nsIPromptService.BUTTON_POS_0) +
+                        (nsIPromptService.BUTTON_TITLE_CANCEL *
+                         nsIPromptService.BUTTON_POS_1);
+    var button = promptService.confirmEx(window,
+                                         GetString("CancelPublishTitle"),
+                                         GetString("CancelPublishMessage"),
+                                         buttonFlags,
+                                         GetString("CancelPublishContinue"),
+                                         null, null, null, {});
+    if (button == 0)
+      return false;
+  }
+
+  if (gTimerID)
+  {
+    clearTimeout(gTimerID);
+    gTimerID = null;
+  }
+
+  if (!gFinished && gPersistObj)
+  {
+    try {
+      gPersistObj.cancelSave();
+    } catch (e) {}
+  }
+  SaveWindowLocation();
+
+  // Tell caller so they can cleanup and restore editability
+  window.opener.FinishPublishing();
+  return true;
+}
+
+function AllowDefaultButton()
+{
+  gDialog.Close.setAttribute("default","true");
+  gAllowEnterKey = true;
+}
+
+function onEnterKey()
+{
+  if (gAllowEnterKey)
+    return CloseDialog();
+
+  return false;
+}
+
+function RequestCloseDialog()
+{
+  // Finish progress messages, settings buttons etc.
+  SetProgressFinished(null, 0);
+
+  if (!gDialog.KeepOpen.checked)
+  {
+    // Leave window open a minimum amount of time 
+    gTimerID = setTimeout("CloseDialog();", 3000);
+  }
+
+  // Set "completed" message if we succeeded
+  // (Some image files may have failed,
+  //  but we don't abort publishing for that)
+  if (!gPublishingFailed)
+  {
+    gDialog.FinalStatusMessage.value = GetString("PublishCompleted");
+    if (gFileNotFound && gTotalFileCount-gSucceededCount)
+    {
+      // Show number of files that failed to upload
+      gStatusMessage = 
+        (GetString("FailedFileMsg").replace(/%x%/,(gTotalFileCount-gSucceededCount)))
+          .replace(/%total%/,gTotalFileCount);
+
+      SetStatusMessage(gStatusMessage);
+    }
+  }
+}
+
+function SetStatusMessage(message)
+{
+  // Status message is a child of <description> element
+  //  so text can wrap to multiple lines if necessary
+  if (gDialog.StatusMessage.firstChild)
+  {
+    gDialog.StatusMessage.firstChild.data = message;
+  }
+  else
+  {
+    var textNode = document.createTextNode(message);
+    if (textNode)
+      gDialog.StatusMessage.appendChild(textNode);
+  }
+  window.sizeToContent();
+}
+
+function CloseDialog()
+{
+  SaveWindowLocation();
+  window.opener.FinishPublishing();
+  try {
+    window.close();
+  } catch (e) {}
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EditorPublishProgress.xul
@@ -0,0 +1,106 @@
+<?xml version="1.0"?>
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -   Charles Manxke (cmanske@netscape.com)
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?> 
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorPublishProgress.dtd">
+<!-- dialog containing a control requiring initial setup -->
+<dialog title=""
+    id="publishProgressDlg"
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    buttons="cancel"
+    buttonlabelclose="&closeButton.label;"
+    onload="Startup()"
+    ondialogaccept="return onEnterKey();"
+    ondialogcancel="return onClose();">
+
+  <!-- Methods common to all editor dialogs -->
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/publishprefs.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EditorPublishProgress.js"/>
+
+  <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+  <broadcaster id="args" value=""/>
+
+  <groupbox>
+    <caption><label id="PublishToSite"/></caption>
+    <label value="&siteUrl.label;"/>
+    <hbox>
+      <label class="indent bold" id="PublishUrl"/>
+    </hbox>
+    <spacer class="spacer"/>
+    <grid id="Subdirectories">
+      <columns><column/><column/></columns>
+      <rows>
+        <row id="DocSubdir">
+          <label value="&docSubdir.label;"/>
+          <label id="docDir"/>
+        </row>
+        <row id="OtherSubdir">
+          <label value="&otherSubdir.label;"/>
+          <label id="otherDir"/>
+        </row>
+      </rows>
+    </grid>
+    <label id="OtherUrl" class="bold" style="margin-left:3em"/>
+  </groupbox>
+  <groupbox>
+    <caption><label value="&fileList.label;"/></caption>
+    <vbox align="center" style="max-width:30em">
+      <label id="FinalStatusMessage" class="bold" value="&status.label;"/>
+    </vbox>
+    <description id="StatusMessage" class="wrap" style="max-width:30em; min-height: 1em"/>
+    <vbox flex="1">
+      <listbox id="FileList" rows="1"/>
+    </vbox>
+    <hbox align="center" id="failureBox" hidden="true">
+      <image class="progressitem" progress="done"/>
+      <label value="&succeeded.label;"/>
+      <spacer class="bigspacer"/>
+      <image class="progressitem" progress="failed"/>
+      <label value="&failed.label;"/>
+    </hbox>
+  </groupbox>
+  <checkbox id="KeepOpen" label="&keepOpen;" oncommand="CheckKeepOpen();" persist="checked"/>
+  <separator class="groove"/>
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EditorPublishSettings.js
@@ -0,0 +1,373 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var gPublishSiteData;
+var gPublishDataChanged = false;
+var gDefaultSiteIndex = -1;
+var gDefaultSiteName;
+var gPreviousDefaultSite;
+var gPreviousTitle;
+var gSettingsChanged = false;
+var gSiteDataChanged = false;
+var gAddNewSite = false;
+var gCurrentSiteIndex = -1;
+var gPasswordManagerOn = true;
+
+// Dialog initialization code
+function Startup()
+{
+  if (!GetCurrentEditor())
+  {
+    window.close();
+    return;
+  }
+
+  gDialog.SiteList            = document.getElementById("SiteList");
+  gDialog.SiteNameInput       = document.getElementById("SiteNameInput");
+  gDialog.PublishUrlInput     = document.getElementById("PublishUrlInput");
+  gDialog.BrowseUrlInput      = document.getElementById("BrowseUrlInput");
+  gDialog.UsernameInput       = document.getElementById("UsernameInput");
+  gDialog.PasswordInput       = document.getElementById("PasswordInput");
+  gDialog.SavePassword        = document.getElementById("SavePassword");
+  gDialog.SetDefaultButton    = document.getElementById("SetDefaultButton");
+  gDialog.RemoveSiteButton    = document.getElementById("RemoveSiteButton");
+  gDialog.OkButton            = document.documentElement.getButton("accept");
+
+  gPublishSiteData = GetPublishSiteData();
+  gDefaultSiteName = GetDefaultPublishSiteName();
+  gPreviousDefaultSite = gDefaultSiteName;
+
+  gPasswordManagerOn = GetBoolPref("signon.rememberSignons");
+  gDialog.SavePassword.disabled = !gPasswordManagerOn;
+
+  InitDialog();
+
+  SetWindowLocation();
+}
+
+function InitDialog()
+{
+  // If there's no current site data, start a new item in the Settings panel
+  if (!gPublishSiteData)
+  {
+    AddNewSite();
+  }
+  else
+  {
+    FillSiteList();
+
+    // uncomment next code line if you want preselection of the default
+    // publishing site
+    //InitSiteSettings(gDefaultSiteIndex);
+
+    SetTextboxFocus(gDialog.SiteNameInput);
+  }
+}
+
+function FillSiteList()
+{
+  // Prevent triggering SelectSiteList() actions
+  gIsSelecting = true;
+  ClearListbox(gDialog.SiteList);
+  gIsSelecting = false;
+  gDefaultSiteIndex = -1;
+
+  // Fill the site list
+  var count = gPublishSiteData.length;
+  for (var i = 0; i < count; i++)
+  {
+    var name = gPublishSiteData[i].siteName;
+    var item = gDialog.SiteList.appendItem(name);
+    SetPublishItemStyle(item);
+    if (name == gDefaultSiteName)
+      gDefaultSiteIndex = i;
+  }
+}
+
+function SetPublishItemStyle(item)
+{
+  // Display default site with bold style
+  if (item)
+  {
+    if (item.getAttribute("label") == gDefaultSiteName)
+      item.setAttribute("class", "bold");
+    else
+      item.removeAttribute("class");
+  }
+}
+
+function AddNewSite()
+{
+  // Save any pending changes locally first
+  if (!ApplyChanges())
+    return;
+
+  // Initialize Setting widgets to none of the selected sites
+  InitSiteSettings(-1);
+  gAddNewSite = true;
+
+  SetTextboxFocus(gDialog.SiteNameInput);
+}
+
+function RemoveSite()
+{
+  if (!gPublishSiteData)
+    return;
+
+  var index = gDialog.SiteList.selectedIndex;
+  var item;
+  if (index != -1)
+  {
+    item = gDialog.SiteList.selectedItems[0];
+    var nameToRemove = item.getAttribute("label");
+
+    // Remove one item from site data array
+    gPublishSiteData.splice(index, 1);
+    // Remove item from site list
+    gDialog.SiteList.clearSelection();
+    gDialog.SiteList.removeItemAt(index);
+
+    // Adjust if we removed last item and reselect a site
+    if (index >= gPublishSiteData.length)
+      index--;
+    InitSiteSettings(index);
+
+    if (nameToRemove == gDefaultSiteName)
+    {
+      // Deleting current default -- set to new selected item
+      //  Arbitrary, but what else to do?
+      SetDefault();
+    }
+    gSiteDataChanged = true;
+  }
+}
+
+function SetDefault()
+{
+  if (!gPublishSiteData)
+    return;
+
+  var index = gDialog.SiteList.selectedIndex;
+  if (index != -1)
+  {
+    gDefaultSiteIndex = index;
+    gDefaultSiteName = gPublishSiteData[index].siteName;
+    
+    // Set bold style on new default
+    var item = gDialog.SiteList.firstChild;
+    while (item)
+    {
+      SetPublishItemStyle(item);
+      item = item.nextSibling;
+    }
+  }
+}
+
+// Recursion prevention:
+// Use when you don't want to trigger ApplyChanges and InitSiteSettings
+var gIsSelecting = false;
+
+function SelectSiteList()
+{
+  if (gIsSelecting)
+    return;
+
+  gIsSelecting = true;
+  var newIndex = gDialog.SiteList.selectedIndex;
+
+  // Save any pending changes locally first
+  if (!ApplyChanges())
+    return;
+
+  InitSiteSettings(newIndex);
+
+  gIsSelecting = false;
+}
+
+// Use this to prevent recursion in SelectSiteList
+function SetSelectedSiteIndex(index)
+{
+  gIsSelecting = true;
+  gDialog.SiteList.selectedIndex = index;
+  gIsSelecting = false;
+}
+
+function InitSiteSettings(selectedSiteIndex)
+{  
+  // Index to the site we will need to update if settings changed
+  gCurrentSiteIndex = selectedSiteIndex;
+  
+  SetSelectedSiteIndex(selectedSiteIndex);
+  var haveData = (gPublishSiteData && selectedSiteIndex != -1);
+
+  gDialog.SiteNameInput.value = haveData ? gPublishSiteData[selectedSiteIndex].siteName : "";
+  gDialog.PublishUrlInput.value = haveData ? gPublishSiteData[selectedSiteIndex].publishUrl : "";
+  gDialog.BrowseUrlInput.value = haveData ? gPublishSiteData[selectedSiteIndex].browseUrl : "";
+  gDialog.UsernameInput.value = haveData ? gPublishSiteData[selectedSiteIndex].username : "";
+
+  var savePassord = haveData && gPasswordManagerOn;
+  gDialog.PasswordInput.value = savePassord ? gPublishSiteData[selectedSiteIndex].password : "";
+  gDialog.SavePassword.checked = savePassord ? gPublishSiteData[selectedSiteIndex].savePassword : false;
+
+  gDialog.SetDefaultButton.disabled = !haveData;
+  gDialog.RemoveSiteButton.disabled = !haveData;
+  gSettingsChanged = false;
+}
+
+function onInputSettings()
+{
+  // TODO: Save current data during SelectSite1 and compare here
+  //       to detect if real change has occurred?
+  gSettingsChanged = true;
+}
+
+function ApplyChanges()
+{
+  if (gSettingsChanged && !UpdateSettings())
+  {
+    // Restore selection to previously current site
+    SetSelectedSiteIndex(gCurrentSiteIndex);
+    return false;
+  }
+  return true;
+}
+
+function UpdateSettings()
+{
+  // Validate and add new site
+  var newName = TrimString(gDialog.SiteNameInput.value);
+  if (!newName)
+  {
+    ShowInputErrorMessage(GetString("MissingSiteNameError"), gDialog.SiteNameInput);
+    return false;
+  }
+  if (PublishSiteNameExists(newName, gPublishSiteData, gCurrentSiteIndex))
+  {
+    ShowInputErrorMessage(GetString("DuplicateSiteNameError").replace(/%name%/, newName));            
+    SetTextboxFocus(gDialog.SiteNameInput);
+    return false;
+  }
+
+  var newUrl = FormatUrlForPublishing(gDialog.PublishUrlInput.value);
+  if (!newUrl)
+  {
+    ShowInputErrorMessage(GetString("MissingPublishUrlError"), gDialog.PublishUrlInput);
+    return false;
+  }
+
+  // Start assuming we're updating existing site at gCurrentSiteIndex
+  var newSiteData = false;
+
+  if (!gPublishSiteData)
+  {
+    // First time used - Create the first site profile
+    gPublishSiteData = new Array(1);
+    gCurrentSiteIndex = 0;
+    newSiteData = true;
+  }
+  else if (gCurrentSiteIndex == -1)
+  {
+    // No currently-selected site,
+    //  must be adding a new site
+    // Add new data at the end of list
+    gCurrentSiteIndex = gPublishSiteData.length;
+    newSiteData = true;
+  }
+    
+  if (newSiteData)
+  {
+    // Init new site profile
+    gPublishSiteData[gCurrentSiteIndex] = {};
+    gPublishSiteData[gCurrentSiteIndex].docDir = "";
+    gPublishSiteData[gCurrentSiteIndex].otherDir = "";
+    gPublishSiteData[gCurrentSiteIndex].dirList = [""];
+    gPublishSiteData[gCurrentSiteIndex].previousSiteName = newName;
+  }
+
+  gPublishSiteData[gCurrentSiteIndex].siteName = newName;
+  gPublishSiteData[gCurrentSiteIndex].publishUrl = newUrl;
+  gPublishSiteData[gCurrentSiteIndex].browseUrl = FormatUrlForPublishing(gDialog.BrowseUrlInput.value);
+  gPublishSiteData[gCurrentSiteIndex].username = TrimString(gDialog.UsernameInput.value);
+  gPublishSiteData[gCurrentSiteIndex].password= gDialog.PasswordInput.value;
+  gPublishSiteData[gCurrentSiteIndex].savePassword = gDialog.SavePassword.checked;
+
+  if (gCurrentSiteIndex == gDefaultSiteIndex)
+    gDefaultSiteName = newName;
+
+  // When adding the very first site, assume that's the default
+  if (gPublishSiteData.length == 1 && !gDefaultSiteName)
+  {
+    gDefaultSiteName = gPublishSiteData[0].siteName;
+    gDefaultSiteIndex = 0;
+  }
+
+  FillSiteList();
+
+  // Select current site in list  
+  SetSelectedSiteIndex(gCurrentSiteIndex);
+
+  // Signal saving data to prefs
+  gSiteDataChanged = true;
+  
+  // Clear current site flags
+  gSettingsChanged = false;
+  gAddNewSite = false;
+
+  return true;
+}
+
+function onAccept()
+{
+  // Save any pending changes locally first
+  if (!ApplyChanges())
+    return false;
+
+  if (gSiteDataChanged)
+  {
+    // Save all local data to prefs
+    SavePublishSiteDataToPrefs(gPublishSiteData, gDefaultSiteName);
+  }
+  else if (gPreviousDefaultSite != gDefaultSiteName)
+  {
+    // only the default site was changed
+    SetDefaultSiteName(gDefaultSiteName);
+  }
+
+  SaveWindowLocation();
+
+  return true;
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EditorPublishSettings.xul
@@ -0,0 +1,87 @@
+<?xml version="1.0"?>
+
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 2001
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?> 
+<?xul-overlay href="chrome://editor/content/EditorPublishOverlay.xul"?> 
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorPublish.dtd">
+
+<dialog title="&windowTitleSettings.label;"
+        id="publishSettingsDlg"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        onload="Startup()"
+        buttons="accept,cancel"
+        ondialogaccept="return onAccept();"
+        ondialogcancel="return onCancel();">
+
+  <!-- Methods common to all editor dialogs -->
+  <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/EditorPublishSettings.js"/>
+  <script type="application/x-javascript" src="chrome://editor/content/publishprefs.js"/>
+
+  <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+  <broadcaster id="args" value=""/>
+
+  <hbox id="SettingsPanel">
+    <groupbox align="center">
+      <caption label="&publishSites.label;"/>
+      <!-- XXX: If tree isn't wrapped in vbox, it appears BELOW next vbox -->
+      <vbox flex="1">
+        <listbox rows="4" id="SiteList" flex="1"  onselect="SelectSiteList();"/>
+      </vbox>
+      <hbox pack="center">
+        <vbox>
+          <button id="NewSiteButton" label="&newSiteButton.label;"
+                  accesskey="&newSiteButton.accesskey;" oncommand="AddNewSite();"/>
+          <button id="SetDefaultButton" label="&setDefaultButton.label;"
+                  accesskey="&setDefaultButton.accesskey;" oncommand="SetDefault();"/>
+          <button id="RemoveSiteButton" label="&removeButton.label;"
+                  accesskey="&removeButton.accesskey;" oncommand="RemoveSite();"/>
+        </vbox>
+      </hbox>
+    </groupbox>
+    <!-- from EditorPublishOverlay.xul -->
+    <vbox id="PublishSettingsInputs"/>
+  </hbox>
+  <spacer class="spacer"/>
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EditorSaveAsCharset.js
@@ -0,0 +1,169 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Frank Tang  ftang@netscape.com
+ *   J.M  Betak  jbetak@netscape.com
+ *   Neil Rashbrook <neil@parkwaycc.co.uk>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+
+var gCharset="";
+var gTitleWasEdited = false;
+var gCharsetWasChanged = false;
+var gInsertNewContentType = false;
+var gContenttypeElement;
+var gInitDone = false;
+
+//Cancel() is in EdDialogCommon.js
+
+function Startup()
+{
+  var editor = GetCurrentEditor();
+  if (!editor)
+  {
+    window.close();
+    return;
+  }
+
+  var observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
+  observerService.notifyObservers(null, "charsetmenu-selected", "other");
+
+  gDialog.TitleInput    = document.getElementById("TitleInput");
+  gDialog.charsetTree   = document.getElementById('CharsetTree'); 
+  gDialog.exportToText  = document.getElementById('ExportToText');
+
+  gContenttypeElement = GetHTTPEquivMetaElement("content-type");
+  if (!gContenttypeElement && (editor.contentsMIMEType != 'text/plain')) 
+  {
+    gContenttypeElement = CreateHTTPEquivMetaElement("content-type");
+    if (!gContenttypeElement ) 
+	{
+      window.close();
+      return;
+    }
+    gInsertNewContentType = true;
+  }
+
+  try {
+    gCharset = editor.documentCharacterSet;
+  } catch (e) {}
+
+  InitDialog();
+
+  // Use the same text as the messagebox for getting title by regular "Save"
+  document.getElementById("EnterTitleLabel").setAttribute("value",GetString("NeedDocTitle"));
+  // This is an <HTML> element so it wraps -- append a child textnode
+  var helpTextParent = document.getElementById("TitleHelp");
+  var helpText = document.createTextNode(GetString("DocTitleHelp"));
+  if (helpTextParent)
+    helpTextParent.appendChild(helpText);
+  
+  // SET FOCUS TO FIRST CONTROL
+  SetTextboxFocus(gDialog.TitleInput);
+  
+  gInitDone = true;
+  
+  SetWindowLocation();
+}
+
+  
+function InitDialog() 
+{
+  gDialog.TitleInput.value = GetDocumentTitle();
+
+  var RDF = Components.classes["@mozilla.org/rdf/rdf-service;1"].getService(Components.interfaces.nsIRDFService);
+  var tree = gDialog.charsetTree;
+  var index = tree.view.getIndexOfResource(RDF.GetResource(gCharset));
+  if (index >= 0) {
+    tree.view.selection.select(index);
+    tree.treeBoxObject.ensureRowIsVisible(index);
+  }
+}
+
+
+function onAccept()
+{
+  var editor = GetCurrentEditor();
+  editor.beginTransaction();
+
+  if(gCharsetWasChanged) 
+  {
+     try {
+       SetMetaElementContent(gContenttypeElement, "text/html; charset=" + gCharset, gInsertNewContentType, true);     
+      editor.documentCharacterSet = gCharset;
+    } catch (e) {}
+  }
+
+  editor.endTransaction();
+
+  if(gTitleWasEdited) 
+    SetDocumentTitle(TrimString(gDialog.TitleInput.value));
+
+  window.opener.ok = true;
+  window.opener.exportToText = gDialog.exportToText.checked;
+  SaveWindowLocation();
+  return true;
+}
+
+
+function readRDFString(aDS,aRes,aProp) 
+{
+  var n = aDS.GetTarget(aRes, aProp, true);
+  if (n)
+    return n.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
+  else
+    return "";
+}
+
+      
+function SelectCharset()
+{
+  if(gInitDone) 
+  {
+    try 
+	{
+      gCharset = gDialog.charsetTree.builderView.getResourceAtIndex(gDialog.charsetTree.currentIndex).Value;
+      if (gCharset)
+        gCharsetWasChanged = true;
+    }
+    catch(e) {}
+  }
+}
+
+
+function TitleChanged()
+{
+  gTitleWasEdited = true; 
+}
new file mode 100644
--- /dev/null
+++ b/editor/ui/dialogs/content/EditorSaveAsCharset.xul
@@ -0,0 +1,94 @@
+<?xml version="1.0"?>
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -   loadrunner@betak.net
+   -   Neil Rashbrook <neil@parkwaycc.co.uk>
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xul"?> 
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorSaveAsCharset.dtd">
+<!-- dialog containing a control requiring initial setup -->
+<!-- WE SHOULD NOT USE ABSOLUTE WITH AND HEIGHT - USE BOXES INSTEAD? -->
+<dialog title="&windowTitle.label;"
+    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+    onload = "Startup()"
+    ondialogaccept="return onAccept();"
+    ondialogcancel="return onCancel();"
+    style="width: 32em;">
+
+    <!-- Methods common to all editor dialogs -->
+    <script type="application/x-javascript" src="chrome://editor/content/editorUtilities.js"/>
+    <script type="application/x-javascript" src="chrome://editor/content/EdDialogCommon.js"/>
+    <script type="application/x-javascript" src="chrome://editor/content/EditorSaveAsCharset.js"/>
+    
+    <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+    <broadcaster id="args" value=""/>
+
+    <groupbox><caption label="&documentTitleTitle.label;"/>
+        <!-- Text labels filled in from editor.properties -->
+        <label id="EnterTitleLabel"/> 
+        <textbox id="TitleInput" oninput="TitleChanged();"/>
+        <description id="TitleHelp" class="wrap" style="width:1em" />
+    </groupbox>
+
+    <groupbox flex="1"><caption label="&documentCharsetTitle.label;"/>
+        <label value="&documentCharsetDesc.label;"/>
+        <tree id="CharsetTree" height="148" hidecolumnpicker="true" onselect="SelectCharset();"
+              datasources="rdf:charset-menu" ref="NC:EncodersRoot" flags="dont-build-content">
+            <treecols>
+                <treecol id="CharsetCol" flex="1" hideheader="true"/>
+            </treecols>
+            <template>
+                <rule>
+                    <treechildren>
+                        <treeitem uri="rdf:*">
+                            <treerow>
+                                <treecell label="rdf:http://home.netscape.com/NC-rdf#Name"/>
+                            </treerow>
+                        </treeitem>
+                    </treechildren>
+                </rule>
+            </template>
+        </tree>
+    </groupbox>
+
+    <checkbox id="ExportToText" label="&documentExportToText.label;" />
+    <separator class="groove"/>
+</dialog>
new file mode 100644
--- /dev/null
+++ b/editor/ui/jar.mn
@@ -0,0 +1,217 @@
+comm.jar:
+% content editor %content/editor/ xpcnativewrappers=yes
+% overlay chrome://communicator/content/tasksOverlay.xul chrome://editor/content/editorTasksOverlay.xul
+% overlay chrome://messenger/content/mailWindowOverlay.xul chrome://editor/content/editorMailOverlay.xul
+#ifdef MOZ_SUITE
+% overlay chrome://communicator/content/pref/preftree.xul chrome://editor/content/editorPrefsOverlay.xul
+% overlay chrome://communicator/content/pref/preferences.xul chrome://editor/content/editorPrefsOverlay.xul
+% overlay chrome://communicator/content/pref/pref-appearance.xul chrome://editor/content/editorPrefsOverlay.xul
+% overlay chrome://navigator/content/navigatorOverlay.xul chrome://editor/content/editorNavigatorOverlay.xul
+% content editor-region %content/editor-region/ xpcnativewrappers=yes
+#endif
+      content/editor/editor.xul                                (composer/content/editor.xul) 
+      content/editor/editor.js                                 (composer/content/editor.js) 
+      content/editor/publishprefs.js                           (composer/content/publishprefs.js) 
+      content/editor/editorUtilities.js                        (composer/content/editorUtilities.js) 
+      content/editor/ComposerCommands.js                       (composer/content/ComposerCommands.js) 
+      content/editor/EditorContextMenu.js                      (composer/content/EditorContextMenu.js) 
+      content/editor/EditorContextMenuOverlay.xul              (composer/content/EditorContextMenuOverlay.xul) 
+      content/editor/EditorAllTags.css                         (composer/content/EditorAllTags.css) 
+      content/editor/EditorParagraphMarks.css                  (composer/content/EditorParagraphMarks.css)
+      content/editor/EditorContent.css                         (composer/content/EditorContent.css)  
+*     content/editor/editorOverlay.xul                         (composer/content/editorOverlay.xul) 
+      content/editor/editorOverlay.js                          (composer/content/editorOverlay.js) 
+      content/editor/composerOverlay.xul                       (composer/content/composerOverlay.xul) 
+      content/editor/pref-toolbars.xul                         (composer/content/pref-toolbars.xul) 
+      content/editor/pref-editing.xul                          (composer/content/pref-editing.xul) 
+      content/editor/pref-composer.js                          (composer/content/pref-composer.js) 
+      content/editor/pref-composer.xul                         (composer/content/pref-composer.xul) 
+      content/editor/editorSmileyOverlay.xul                   (composer/content/editorSmileyOverlay.xul) 
+      content/editor/editorPrefsOverlay.xul                    (composer/content/editorPrefsOverlay.xul) 
+      content/editor/editorNavigatorOverlay.xul                (composer/content/editorNavigatorOverlay.xul) 
+      content/editor/editorMailOverlay.xul                     (composer/content/editorMailOverlay.xul) 
+      content/editor/editorTasksOverlay.xul                    (composer/content/editorTasksOverlay.xul) 
+      content/editor/editorApplicationOverlay.js               (composer/content/editorApplicationOverlay.js) 
+      content/editor/StructBarContextMenu.js                   (composer/content/StructBarContextMenu.js) 
+      content/editor/images/sendtoback.gif                     (composer/content/images/sendtoback.gif)
+      content/editor/images/sendtoback-disabled.gif            (composer/content/images/sendtoback-disabled.gif)
+      content/editor/images/bringtofront.gif                   (composer/content/images/bringtofront.gif)
+      content/editor/images/bringtofront-disabled.gif          (composer/content/images/bringtofront-disabled.gif)
+      content/editor/images/tag-anchor.gif                     (composer/content/images/tag-anchor.gif)
+      content/editor/images/tag-abr.gif                        (composer/content/images/tag-abr.gif)
+      content/editor/images/tag-acr.gif                        (composer/content/images/tag-acr.gif)
+      content/editor/images/tag-adr.gif                        (composer/content/images/tag-adr.gif)
+      content/editor/images/tag-ara.gif                        (composer/content/images/tag-ara.gif)
+      content/editor/images/tag-bas.gif                        (composer/content/images/tag-bas.gif)
+      content/editor/images/tag-blq.gif                        (composer/content/images/tag-blq.gif)
+      content/editor/images/tag-bsf.gif                        (composer/content/images/tag-bsf.gif)
+      content/editor/images/tag-btn.gif                        (composer/content/images/tag-btn.gif)
+      content/editor/images/tag-cit.gif                        (composer/content/images/tag-cit.gif)
+      content/editor/images/tag-clg.gif                        (composer/content/images/tag-clg.gif)
+      content/editor/images/tag-cod.gif                        (composer/content/images/tag-cod.gif)
+      content/editor/images/tag-cpt.gif                        (composer/content/images/tag-cpt.gif)
+      content/editor/images/tag-ctr.gif                        (composer/content/images/tag-ctr.gif)
+      content/editor/images/tag-fld.gif                        (composer/content/images/tag-fld.gif)
+      content/editor/images/tag-fnt.gif                        (composer/content/images/tag-fnt.gif)
+      content/editor/images/tag-for.gif                        (composer/content/images/tag-for.gif)
+      content/editor/images/tag-frm.gif                        (composer/content/images/tag-frm.gif)
+      content/editor/images/tag-fst.gif                        (composer/content/images/tag-fst.gif)
+      content/editor/images/tag-ifr.gif                        (composer/content/images/tag-ifr.gif)
+      content/editor/images/tag-inp.gif                        (composer/content/images/tag-inp.gif)
+      content/editor/images/tag-lbl.gif                        (composer/content/images/tag-lbl.gif)
+      content/editor/images/tag-lgn.gif                        (composer/content/images/tag-lgn.gif)
+      content/editor/images/tag-lnk.gif                        (composer/content/images/tag-lnk.gif)
+      content/editor/images/tag-lst.gif                        (composer/content/images/tag-lst.gif)
+      content/editor/images/tag-men.gif                        (composer/content/images/tag-men.gif)
+      content/editor/images/tag-nbr.gif                        (composer/content/images/tag-nbr.gif)
+      content/editor/images/tag-nfr.gif                        (composer/content/images/tag-nfr.gif)
+      content/editor/images/tag-nsc.gif                        (composer/content/images/tag-nsc.gif)
+      content/editor/images/tag-opg.gif                        (composer/content/images/tag-opg.gif)
+      content/editor/images/tag-opt.gif                        (composer/content/images/tag-opt.gif)
+      content/editor/images/tag-prm.gif                        (composer/content/images/tag-prm.gif)
+      content/editor/images/tag-scr.gif                        (composer/content/images/tag-scr.gif)
+      content/editor/images/tag-slc.gif                        (composer/content/images/tag-slc.gif)
+      content/editor/images/tag-sml.gif                        (composer/content/images/tag-sml.gif)
+      content/editor/images/tag-smp.gif                        (composer/content/images/tag-smp.gif)
+      content/editor/images/tag-spn.gif                        (composer/content/images/tag-spn.gif)
+      content/editor/images/tag-stk.gif                        (composer/content/images/tag-stk.gif)
+      content/editor/images/tag-stl.gif                        (composer/content/images/tag-stl.gif)
+      content/editor/images/tag-stn.gif                        (composer/content/images/tag-stn.gif)
+      content/editor/images/tag-tbd.gif                        (composer/content/images/tag-tbd.gif)
+      content/editor/images/tag-tbl.gif                        (composer/content/images/tag-tbl.gif)
+      content/editor/images/tag-tft.gif                        (composer/content/images/tag-tft.gif)
+      content/editor/images/tag-thd.gif                        (composer/content/images/tag-thd.gif)
+      content/editor/images/tag-hed.gif                        (composer/content/images/tag-hed.gif)
+      content/editor/images/tag-isx.gif                        (composer/content/images/tag-isx.gif)
+      content/editor/images/tag-met.gif                        (composer/content/images/tag-met.gif)
+      content/editor/images/tag-ttl.gif                        (composer/content/images/tag-ttl.gif)
+      content/editor/images/tag-pln.gif                        (composer/content/images/tag-pln.gif)
+      content/editor/images/tag-xmp.gif                        (composer/content/images/tag-xmp.gif)
+      content/editor/images/tag-txt.gif                        (composer/content/images/tag-txt.gif)
+      content/editor/images/tag-a.gif                          (composer/content/images/tag-a.gif)
+      content/editor/images/tag-app.gif                        (composer/content/images/tag-app.gif)
+      content/editor/images/tag-b.gif                          (composer/content/images/tag-b.gif)
+      content/editor/images/tag-bdo.gif                        (composer/content/images/tag-bdo.gif)
+      content/editor/images/tag-big.gif                        (composer/content/images/tag-big.gif)
+      content/editor/images/tag-body.gif                       (composer/content/images/tag-body.gif)
+      content/editor/images/tag-br.gif                         (composer/content/images/tag-br.gif)
+      content/editor/images/tag-col.gif                        (composer/content/images/tag-col.gif)
+      content/editor/images/tag-dd.gif                         (composer/content/images/tag-dd.gif)
+      content/editor/images/tag-del.gif                        (composer/content/images/tag-del.gif)
+      content/editor/images/tag-dfn.gif                        (composer/content/images/tag-dfn.gif)
+      content/editor/images/tag-dir.gif                        (composer/content/images/tag-dir.gif)
+      content/editor/images/tag-div.gif                        (composer/content/images/tag-div.gif)
+      content/editor/images/tag-dl.gif                         (composer/content/images/tag-dl.gif)
+      content/editor/images/tag-dt.gif                         (composer/content/images/tag-dt.gif)
+      content/editor/images/tag-em.gif                         (composer/content/images/tag-em.gif)
+      content/editor/images/tag-h1.gif                         (composer/content/images/tag-h1.gif)
+      content/editor/images/tag-h2.gif                         (composer/content/images/tag-h2.gif)
+      content/editor/images/tag-h3.gif                         (composer/content/images/tag-h3.gif)
+      content/editor/images/tag-h4.gif                         (composer/content/images/tag-h4.gif)
+      content/editor/images/tag-h5.gif                         (composer/content/images/tag-h5.gif)
+      content/editor/images/tag-h6.gif                         (composer/content/images/tag-h6.gif)
+      content/editor/images/tag-hr.gif                         (composer/content/images/tag-hr.gif)
+      content/editor/images/tag-html.gif                       (composer/content/images/tag-html.gif)
+      content/editor/images/tag-i.gif                          (composer/content/images/tag-i.gif)
+      content/editor/images/tag-img.gif                        (composer/content/images/tag-img.gif)
+      content/editor/images/tag-ins.gif                        (composer/content/images/tag-ins.gif)
+      content/editor/images/tag-kbd.gif                        (composer/content/images/tag-kbd.gif)
+      content/editor/images/tag-li.gif                         (composer/content/images/tag-li.gif)
+      content/editor/images/tag-map.gif                        (composer/content/images/tag-map.gif)
+      content/editor/images/tag-obj.gif                        (composer/content/images/tag-obj.gif)
+      content/editor/images/tag-ol.gif                         (composer/content/images/tag-ol.gif)
+      content/editor/images/tag-p.gif                          (composer/content/images/tag-p.gif)
+      content/editor/images/tag-pre.gif                        (composer/content/images/tag-pre.gif)
+      content/editor/images/tag-q.gif                          (composer/content/images/tag-q.gif)
+      content/editor/images/tag-s.gif                          (composer/content/images/tag-s.gif)
+      content/editor/images/tag-sub.gif                        (composer/content/images/tag-sub.gif)
+      content/editor/images/tag-sup.gif                        (composer/content/images/tag-sup.gif)
+      content/editor/images/tag-td.gif                         (composer/content/images/tag-td.gif)
+      content/editor/images/tag-th.gif                         (composer/content/images/tag-th.gif)
+      content/editor/images/tag-tr.gif                         (composer/content/images/tag-tr.gif)
+      content/editor/images/tag-tt.gif                         (composer/content/images/tag-tt.gif)
+      content/editor/images/tag-u.gif                          (composer/content/images/tag-u.gif)
+      content/editor/images/tag-ul.gif                         (composer/content/images/tag-ul.gif)
+      content/editor/images/tag-var.gif                        (composer/content/images/tag-var.gif)
+      content/editor/images/tag-userdefined.gif                (composer/content/images/tag-userdefined.gif)
+      content/editor/EdDialogCommon.js                         (dialogs/content/EdDialogCommon.js) 
+      content/editor/EdLinkProps.xul                           (dialogs/content/EdLinkProps.xul) 
+      content/editor/EdLinkProps.js                            (dialogs/content/EdLinkProps.js) 
+      content/editor/EdLinkChecker.xul                         (dialogs/content/EdLinkChecker.xul) 
+      content/editor/EdLinkChecker.js                          (dialogs/content/EdLinkChecker.js) 
+      content/editor/EdImageProps.xul                          (dialogs/content/EdImageProps.xul) 
+      content/editor/EdImageProps.js                           (dialogs/content/EdImageProps.js) 
+      content/editor/EdImageOverlay.xul                        (dialogs/content/EdImageOverlay.xul) 
+      content/editor/EdImageOverlay.js                         (dialogs/content/EdImageOverlay.js) 
+      content/editor/EdHLineProps.xul                          (dialogs/content/EdHLineProps.xul) 
+      content/editor/EdHLineProps.js                           (dialogs/content/EdHLineProps.js) 
+      content/editor/EdReplace.xul                             (dialogs/content/EdReplace.xul) 
+      content/editor/EdReplace.js                              (dialogs/content/EdReplace.js) 
+      content/editor/EdSnapToGrid.xul                          (dialogs/content/EdSnapToGrid.xul)
+      content/editor/EdSnapToGrid.js                           (dialogs/content/EdSnapToGrid.js)
+      content/editor/EdSpellCheck.xul                          (dialogs/content/EdSpellCheck.xul) 
+      content/editor/EdSpellCheck.js                           (dialogs/content/EdSpellCheck.js) 
+      content/editor/EdDictionary.xul                          (dialogs/content/EdDictionary.xul) 
+      content/editor/EdDictionary.js                           (dialogs/content/EdDictionary.js) 
+      content/editor/EdNamedAnchorProps.xul                    (dialogs/content/EdNamedAnchorProps.xul) 
+      content/editor/EdNamedAnchorProps.js                     (dialogs/content/EdNamedAnchorProps.js) 
+      content/editor/EdInsertTOC.xul                           (dialogs/content/EdInsertTOC.xul) 
+      content/editor/EdInsertTOC.js                            (dialogs/content/EdInsertTOC.js) 
+      content/editor/EdInsertTable.xul                         (dialogs/content/EdInsertTable.xul) 
+      content/editor/EdInsertTable.js                          (dialogs/content/EdInsertTable.js) 
+      content/editor/EdTableProps.xul                          (dialogs/content/EdTableProps.xul) 
+      content/editor/EdTableProps.js                           (dialogs/content/EdTableProps.js) 
+      content/editor/EdFormProps.xul                           (dialogs/content/EdFormProps.xul) 
+      content/editor/EdFormProps.js                            (dialogs/content/EdFormProps.js) 
+      content/editor/EdInputProps.xul                          (dialogs/content/EdInputProps.xul) 
+      content/editor/EdInputProps.js                           (dialogs/content/EdInputProps.js) 
+      content/editor/EdInputImage.xul                          (dialogs/content/EdInputImage.xul) 
+      content/editor/EdInputImage.js                           (dialogs/content/EdInputImage.js) 
+      content/editor/EdTextAreaProps.xul                       (dialogs/content/EdTextAreaProps.xul) 
+      content/editor/EdTextAreaProps.js                        (dialogs/content/EdTextAreaProps.js) 
+      content/editor/EdSelectProps.xul                         (dialogs/content/EdSelectProps.xul) 
+      content/editor/EdSelectProps.js                          (dialogs/content/EdSelectProps.js) 
+      content/editor/EdButtonProps.xul                         (dialogs/content/EdButtonProps.xul) 
+      content/editor/EdButtonProps.js                          (dialogs/content/EdButtonProps.js) 
+      content/editor/EdLabelProps.xul                          (dialogs/content/EdLabelProps.xul) 
+      content/editor/EdLabelProps.js                           (dialogs/content/EdLabelProps.js) 
+      content/editor/EdFieldSetProps.xul                       (dialogs/content/EdFieldSetProps.xul) 
+      content/editor/EdFieldSetProps.js                        (dialogs/content/EdFieldSetProps.js) 
+      content/editor/EdInsSrc.xul                              (dialogs/content/EdInsSrc.xul) 
+      content/editor/EdInsSrc.js                               (dialogs/content/EdInsSrc.js) 
+      content/editor/EdInsertChars.xul                         (dialogs/content/EdInsertChars.xul) 
+      content/editor/EdInsertChars.js                          (dialogs/content/EdInsertChars.js) 
+      content/editor/EdDialogOverlay.xul                       (dialogs/content/EdDialogOverlay.xul) 
+      content/editor/EdAdvancedEdit.xul                        (dialogs/content/EdAdvancedEdit.xul) 
+      content/editor/EdAdvancedEdit.js                         (dialogs/content/EdAdvancedEdit.js) 
+      content/editor/EdListProps.xul                           (dialogs/content/EdListProps.xul) 
+      content/editor/EdListProps.js                            (dialogs/content/EdListProps.js) 
+      content/editor/EdPageProps.xul                           (dialogs/content/EdPageProps.xul) 
+      content/editor/EdPageProps.js                            (dialogs/content/EdPageProps.js) 
+      content/editor/EdColorProps.xul                          (dialogs/content/EdColorProps.xul) 
+      content/editor/EdColorProps.js                           (dialogs/content/EdColorProps.js) 
+      content/editor/EdColorPicker.xul                         (dialogs/content/EdColorPicker.xul) 
+      content/editor/EdColorPicker.js                          (dialogs/content/EdColorPicker.js) 
+      content/editor/EdAECSSAttributes.js                      (dialogs/content/EdAECSSAttributes.js) 
+      content/editor/EdAEHTMLAttributes.js                     (dialogs/content/EdAEHTMLAttributes.js) 
+      content/editor/EdAEJSEAttributes.js                      (dialogs/content/EdAEJSEAttributes.js) 
+      content/editor/EdAEAttributes.js                         (dialogs/content/EdAEAttributes.js) 
+      content/editor/EdImageMap.js                             (dialogs/content/EdImageMap.js) 
+      content/editor/EdImageMap.xul                            (dialogs/content/EdImageMap.xul) 
+      content/editor/EdImageMapHotSpot.js                      (dialogs/content/EdImageMapHotSpot.js) 
+      content/editor/EdImageMapHotSpot.xul                     (dialogs/content/EdImageMapHotSpot.xul) 
+      content/editor/EdImageMapShapes.js                       (dialogs/content/EdImageMapShapes.js) 
+      content/editor/EdImageMapPage.html                       (dialogs/content/EdImageMapPage.html) 
+      content/editor/EditConflict.xul                          (dialogs/content/EditConflict.xul) 
+      content/editor/EditConflict.js                           (dialogs/content/EditConflict.js) 
+      content/editor/EditorSaveAsCharset.xul                   (dialogs/content/EditorSaveAsCharset.xul) 
+      content/editor/EditorSaveAsCharset.js                    (dialogs/content/EditorSaveAsCharset.js) 
+      content/editor/EdConvertToTable.xul                      (dialogs/content/EdConvertToTable.xul) 
+      content/editor/EdConvertToTable.js                       (dialogs/content/EdConvertToTable.js) 
+      content/editor/EditorPublish.xul                         (dialogs/content/EditorPublish.xul) 
+      content/editor/EditorPublish.js                          (dialogs/content/EditorPublish.js) 
+      content/editor/EditorPublishSettings.xul                 (dialogs/content/EditorPublishSettings.xul) 
+      content/editor/EditorPublishSettings.js                  (dialogs/content/EditorPublishSettings.js) 
+      content/editor/EditorPublishOverlay.xul                  (dialogs/content/EditorPublishOverlay.xul) 
+      content/editor/EditorPublishProgress.xul                 (dialogs/content/EditorPublishProgress.xul) 
+      content/editor/EditorPublishProgress.js                  (dialogs/content/EditorPublishProgress.js) 
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/Makefile.in
@@ -0,0 +1,47 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is the Mozilla Browser code.
+#
+# The Initial Developer of the Original Code is
+# Benjamin Smedberg <bsmedberg@covad.net>
+# Portions created by the Initial Developer are Copyright (C) 2004
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH          = ../../..
+topsrcdir      = @top_srcdir@
+srcdir         = @srcdir@
+VPATH          = @srcdir@
+relativesrcdir = editor/ui/locales
+
+include $(DEPTH)/config/autoconf.mk
+
+DEFINES += -DAB_CD=$(AB_CD)
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/composer/editor.dtd
@@ -0,0 +1,66 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!-- Window title -->
+<!-- LOCALIZATION NOTE  (editorWindow.titlemodifier): DONT_TRANSLATE -->
+<!ENTITY editorWindow.titlemodifier "Composer"> 
+<!ENTITY editorWindow.titlemodifiermenuseparator " - ">
+
+<!-- Menu items:  the . means that the menu item isn't implemented yet -->
+
+<!-- View menu items -->
+<!ENTITY viewMenu.label "View">
+<!ENTITY viewmenu.accesskey "v">
+<!ENTITY compositionToolbarCmd.label "Composition Toolbar">
+<!ENTITY compositiontb.accesskey "c">
+<!ENTITY formattingToolbarCmd.label "Format Toolbar">
+<!ENTITY formattingtb.accesskey "f">
+<!ENTITY editmodeToolbarCmd.label "Edit Mode Toolbar">
+<!ENTITY editmodetb.accesskey "E">
+
+<!-- Format menu items -->
+<!ENTITY formatMenu.label "Format">
+<!ENTITY formatmenu.accesskey "o">
+
+<!ENTITY helpMenu.label "Help">
+<!ENTITY aboutCmd.label ".About">
+
+<!-- Display Mode Toolbar -->
+<!ENTITY editMode.label "Edit Mode:">
+
+<!ENTITY statusText.label "Done loading page">
+
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/composer/editor.properties
@@ -0,0 +1,226 @@
+#
+# moved from content/
+#
+# LOCALIZATION NOTE FILE: embedded "\n" represent HTML breaks (<br>)
+# Don't translate embedded "\n".
+# Don't translate strings like this: %variable%
+#  as they will be replaced using JavaScript
+#
+Yes=Yes
+No=No
+Save=Save
+DontSave=Don't Save
+More=More
+Fewer=Fewer
+Less=Less
+MoreAttributes=More Attributes
+FewerAttributes=Fewer Attributes
+MoreProperties=More Properties
+FewerProperties=Fewer Properties
+PropertiesAccessKey=P
+None=None
+none=none
+OpenHTMLFile=Open HTML File
+SelectImageFile=Select Image File
+SaveDocument=Save Page
+SaveDocumentAs=Save Page As
+ExportToText=Export to Text
+EditMode=Edit Mode
+Preview=Preview
+Publish=Publish
+PublishPage=Publish Page
+DontPublish=Don't Publish
+SavePassword=Use Password Manager to save this password
+CorrectSpelling=(correct spelling)
+NoSuggestedWords=(no suggested words)
+NoMisspelledWord=No misspelled words
+CheckSpellingDone=Completed spell checking.
+CheckSpelling=Check Spelling
+LoadingDone=Done loading page
+InputError=Error
+Alert=Alert
+CantEditFramesetMsg=Composer cannot edit HTML framesets, or pages with inline frames. For framesets, try editing the page for each frame separately. For pages with iframes, save a copy of the page and remove the <iframe> tag.
+CantEditMimeTypeMsg=This type of page can't be edited.
+CantEditDocumentMsg=This page can't be edited for an unknown reason.
+HTMLFiles=HTML Files
+IMGFiles=Image Files
+TextFiles=Text Files
+AllFiles=All Files
+BeforeClosing=before closing
+BeforePreview=before viewing in the browser
+BeforeValidate=before validating the document
+# LOCALIZATION NOTE (SaveFilePrompt, PublishPrompt): Don't translate %title% and %reason% (this is the reason for asking user to close, such as "before closing")
+SaveFilePrompt=Save changes to "%title%" %reason%? 
+PublishPrompt=Save changes to "%title%" %reason%? 
+SaveFileFailed=Saving file failed!
+
+# Publishing error strings:
+# LOCALIZATION NOTE Don't translate %dir% or %file% in the Publishing error strings:
+FileNotFound=%file% not found.
+SubdirDoesNotExist=The subdirectory "%dir%" doesn't exist on this site or the filename "%file%" is already in use by another subdirectory.
+FilenameIsSubdir=The filename "%file%" is already in use by another subdirectory.
+ServerNotAvailable=The server is not available. Check your connection and try again later.
+Offline=You are currently offline. Click the icon near the lower-right corner of any window to go online.
+DiskFull=There is not enough disk space available to save the file "%file%."
+NameTooLong=The filename or subdirectory name is too long.
+AccessDenied=You do not have permission to publish to this location.
+UnknownPublishError=Unknown publishing error occurred.
+PublishFailed=Publishing failed.
+PublishCompleted=Publishing completed.
+AllFilesPublished=All files published
+# LOCALIZATION NOTE Don't translate %x% or %total%
+FailedFileMsg=%x% of %total% files failed to publish.
+# End-Publishing error strings
+Prompt=Prompt
+# LOCALIZATION NOTE (PromptFTPUsernamePassword): Don't translate %host% 
+PromptFTPUsernamePassword=Enter username and password for FTP server at %host%
+RevertCaption=Revert To Last Saved
+Revert=Revert
+SendPageReason=before sending this page
+Send=Send
+## LOCALIZATION NOTE (PublishProgressCaption, PublishToSite, AbandonChanges): Don't translate %title%
+PublishProgressCaption=Publishing: %title%
+PublishToSite=Publishing to Site: %title%
+AbandonChanges=Abandon unsaved changes to "%title%" and reload page?
+DocumentTitle=Page Title
+NeedDocTitle=Please enter a title for the current page.
+DocTitleHelp=This identifies the page in the window title and bookmarks.
+CancelPublishTitle=Cancel publishing?
+## LOCALIZATION NOTE: "Continue" in this sentence must match the text for
+## the CancelPublishContinue key below
+CancelPublishMessage=Cancelling while publishing is in progress may result in your file(s) being incompletely transferred. Would you like to Continue or Cancel?
+CancelPublishContinue=Continue
+AttributesFor=Current attributes for: 
+MissingImageError=Please enter or choose an image of type gif, jpg, or png.
+EmptyHREFError=Please choose a location to create a new link.
+LinkText=Link Text
+LinkImage=Link Image
+MixedSelection=[Mixed selection]
+Mixed=(mixed)
+EnterLinkText=Enter text to display for the link:
+EnterLinkTextAccessKey=T
+EmptyLinkTextError=Please enter some text for this link.
+EditTextWarning=This will replace existing content.
+#LOCALIZATION NOTE (ValidateNumber):Don't translate: %n% %min% %max%
+ValidateRangeMsg=The number you entered (%n%) is outside of the allowed range.
+ValidateNumberMsg=Please enter a number between %min% and %max%.
+MissingAnchorNameError=Please enter a name for this anchor.
+#LOCALIZATION NOTE (DuplicateAnchorNameError): Don't translate %name%
+DuplicateAnchorNameError="%name%" already exists in this page. Please enter a different name.
+BulletStyle=Bullet Style
+SolidCircle=Solid circle
+OpenCircle=Open circle
+SolidSquare=Solid square
+NumberStyle=Number Style
+Automatic=Automatic
+Style_1=1, 2, 3…
+Style_I=I, II, III…
+Style_i=i, ii, iii…
+Style_A=A, B, C…
+Style_a=a, b, c…
+Pixels=pixels
+Percent=percent
+PercentOfCell=% of cell
+PercentOfWindow=% of window
+PercentOfTable=% of table
+untitled=untitled
+ShowToolbar=Show Toolbar
+HideToolbar=Hide Toolbar
+ImapError=Unable to load image 
+ImapCheck=\nPlease select a new location (URL) and try again.
+SaveToUseRelativeUrl=Relative URLs can only be used on pages which have been saved
+NoNamedAnchorsOrHeadings=(No named anchors or headings in this page)
+TextColor=Text Color
+HighlightColor=Highlight Color
+PageColor=Page Background Color
+BlockColor=Block Background Color
+TableColor=Table Background Color
+CellColor=Cell Background Color
+TableOrCellColor=Table or Cell Color
+LinkColor=Link Text Color
+ActiveLinkColor=Active Link Color
+VisitedLinkColor=Visited Link Color
+NoColorError=Click on a color or enter a valid HTML color string
+Table=Table
+TableCell=Table Cell
+NestedTable=Nested Table
+HLine=Horizontal Line
+Link=Link
+Image=Image
+ImageAndLink=Image and Link
+NamedAnchor=Named Anchor
+List=List
+ListItem=List Item
+Form=Form
+InputTag=Form Field
+InputImage=Form Image
+TextArea=Text Area
+Select=Selection List
+Button=Button
+Label=Label
+FieldSet=Field Set
+Tag=Tag
+MissingSiteNameError=Please enter a name for this publishing site.
+MissingPublishUrlError=Please enter a location for publishing this page.
+MissingPublishFilename=Please enter a filename for the current page.
+MissingPublishSiteError=No publishing site information given. Switching to Settings panel so you can supply publishing information.
+#LOCALIZATION NOTE (DuplicateSiteNameError): Don't translate %name%
+DuplicateSiteNameError="%name%" already exists. Please enter a different site name.
+AdvancedProperties=Advanced Properties…
+AdvancedEditForCellMsg=Advanced Edit is unavailable when multiple cells are selected
+# LOCALIZATION NOTE (ObjectProperties):Don't translate "%obj%" it will be replaced with one of above object nouns
+ObjectProperties=%obj% Properties…
+# LOCALIZATION NOTE This character must be in the above string and not confict with other accesskeys in Format menu
+ObjectPropertiesAccessKey=o
+# LOCALIZATION NOTE (JoinSelectedCells): This variable should contain the "tablejoincells.accesskey" 
+# letter as defined in editorOverlay.dtd
+JoinSelectedCells=Join Selected Cells
+# LOCALIZATION NOTE (JoinCellToRight): This variable should contain the "tablejoincells.accesskey" 
+# letter as defined in editorOverlay.dtd
+JoinCellToRight=Join with Cell to the Right
+JoinCellAccesskey=j
+# LOCALIZATION NOTE (TableSelectKey): DONT_TRANSLATE
+TableSelectKey=Ctrl+
+# LOCALIZATION NOTE (XulKeyDefault): DONT_TRANSLATE
+XulKeyDefault=Ctrl+
+# LOCALIZATION NOTE (XulKeyMac): DONT_TRANSLATE
+XulKeyMac=Cmd+
+# LOCALIZATION NOTE (XulKeyUnix): DONT_TRANSLATE
+XulKeyUnix=Alt+
+# LOCALIZATION NOTE (Del): DONT_TRANSLATE
+Del=Del
+Delete=Delete
+DeleteCells=Delete Cells
+DeleteTableTitle=Delete Rows or Columns
+DeleteTableMsg=Reducing the number of rows or columns will delete table cells and their contents. Do you really want to do this?
+Clear=Clear
+#Mouse actions
+Click=Click
+Drag=Drag
+Unknown=Unknown
+#
+# LOCALIZATION NOTE "RemoveTextStylesAccesskey" is used for both
+#  menu items: "RemoveTextStyles" and "StopTextStyles"
+RemoveTextStylesAccesskey=x
+RemoveTextStyles=Remove All Text Styles
+StopTextStyles=Discontinue Text Styles
+#
+# LOCALIZATION NOTE "RemoveLinksAccesskey" is used for both
+#  menu items: "RemoveLinks" and "StopLinks"
+RemoveLinksAccesskey=n
+RemoveLinks=Remove Links
+StopLinks=Discontinue Link
+#
+NoFormAction=It is recommended that you enter an action for this form. Self-posting forms are an advanced technique that may not work consistently in all browsers.
+NoAltText=If the image is relevant to the content of the document, you must supply alternate text that will appear in text-only browsers, and that will appear in other browsers when an image is loading or when image loading is disabled.
+SaveImageAs=Save Image (%NAME%)…
+NoSeparatorCharacter=Please enter a single character to use for separating into columns
+#
+# LOCALIZATION NOTE please do not translate %brand%, it will be used programmatically
+#  download spelling dictionaries confirmation dialog
+DictDownldConfirmTit=Download Dictionaries
+DictDownldConfirmMsg=%brand% will close the current window and redirect you to a spellchecker download site.
+#
+NoHeadTag=The HTML source could not be converted back into the document because the required <head> tag is missing. Please add it.
+NoBodyTag=The HTML source could not be converted back into the document because the required <body> tag is missing. Please add it.
+NoLinksToCheck=There are no elements with links to check
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/composer/editorNavigatorOverlay.dtd
@@ -0,0 +1,7 @@
+
+<!ENTITY editPageCmd.label                "Edit Page in Composer"> 
+<!ENTITY editPageCmd.accesskey            "e">
+
+<!ENTITY editLinkCmd.label                "Edit Link in Composer">
+<!ENTITY editLinkCmd.accesskey            "E">
+
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/composer/editorOverlay.dtd
@@ -0,0 +1,592 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1999-2000
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -   Sammy Ford
+   -   Blake Ross
+   -   Ryan Cassin (rcassin@supernova.org)
+   -   Daniel Glazman (glazman@netscape.com)
+   -   Stephen Donner (technutz@netscape.net)
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!-- Attn: Localization - some of the menus in this dialog directly affect mail also. -->
+
+<!-- File menu items -->
+<!ENTITY fileMenu.label "File">
+<!ENTITY filemenu.accesskey "f">
+<!ENTITY newBlankPageCmd.label "Composer Page">
+<!ENTITY newBlankPage.accesskey "P" >
+<!ENTITY newMenu.label "New">
+<!ENTITY openFileCmd.label "Open File…">
+<!ENTITY fileopen.accesskey "o">
+<!ENTITY fileopen.keybinding "o">
+<!ENTITY openremoteCmd.label "Open Web Location…">
+<!ENTITY fileopenremote.accesskey "l">
+<!ENTITY fileopenremote.keybinding "l">
+<!ENTITY fileRecentMenu.label "Recent Pages">
+<!ENTITY filerecentmenu.accesskey "r">
+<!ENTITY fileRevert.label "Revert">
+<!ENTITY filerevert.accesskey "v">
+<!ENTITY saveCmd.label "Save">
+<!ENTITY filesave.accesskey "s">
+<!ENTITY filesave.keybinding "s">
+<!ENTITY saveAsCmd.label "Save As…">
+<!ENTITY filesaveas.accesskey "A">
+
+<!ENTITY publishCmd.label "Publish">
+<!ENTITY publishcmd.accesskey "b">
+<!ENTITY publishAsCmd.label "Publish As…">
+<!ENTITY publishas.accesskey "h">
+<!ENTITY exportToTextCmd.label "Export to Text…">
+<!ENTITY fileexporttotext.accesskey "T">
+<!ENTITY saveAsChangeEncodingCmd.label "Save And Change Character Encoding">
+<!ENTITY filesaveandchangeencoding.accesskey "E">
+<!ENTITY previewCmd.label "Browse Page">
+<!ENTITY filepreview.accesskey "w">
+<!ENTITY sendPageCmd.label "Send Page…">
+<!ENTITY sendPage.accesskey "d">
+<!ENTITY printSetupCmd.label "Page Setup…">
+<!ENTITY fileprintsetup.accesskey "u">
+<!ENTITY printPreviewCmd.label "Print Preview">
+<!ENTITY fileprintpreview.accesskey "v">
+<!ENTITY printCmd.label "Print…">
+<!ENTITY printButtonCmd.label "Print…">
+<!ENTITY fileprint.accesskey "p">
+<!ENTITY fileprint.keybinding "p">
+<!ENTITY closeCmd.label "Close">
+<!ENTITY fileclose.accesskey "c">
+<!ENTITY fileclose.keybinding "w">
+<!ENTITY exitCmd.label "Quit">
+<!ENTITY fileexit.accesskey "q">
+<!ENTITY fileexit.keybinding "q">
+
+<!-- Edit menu items -->
+<!ENTITY editMenu.label "Edit">
+<!ENTITY editmenu.accesskey "e">
+<!ENTITY pasteNoFormatting.label "Paste Without Formatting">
+<!ENTITY pasteNoFormatting.accesskey "o">
+<!ENTITY pasteAs.label "Paste As">
+<!ENTITY pasteAs.accesskey "a">
+<!ENTITY publishSettings.label "Publishing Site Settings…">
+<!ENTITY publishSettings.accesskey "b">
+
+<!-- For a "Paste" submenu when more than 1 
+     clipboard formats are available -->
+<!ENTITY pasteHTMLCmd.label "HTML">
+<!ENTITY pasteHTML.accesskey "h">
+<!ENTITY pasteTextCmd.label "Text">
+<!ENTITY pasteText.accesskey "t">
+<!ENTITY pasteImageCmd.label "Image">
+<!ENTITY pasteImage.accesskey "i">
+<!ENTITY pasteRowsCmd.label "Rows">
+<!ENTITY pasteRows.accesskey "r">
+<!ENTITY pasteColumnsCmd.label "Columns">
+<!ENTITY pasteColumns.accesskey "c">
+<!-- LOCALIZATION NOTE: Text for menu item is in editor.properties
+     Set to: "Table" or "Nested Table" depending on context 
+     This accesskey must be in both strings -->
+<!ENTITY pasteTable.accesskey "a">
+<!ENTITY pasteLinkCmd.label "Link">
+<!ENTITY editpastelink.accesskey "l">
+<!ENTITY pasteAsQuotationCmd.label "Paste As Quotation">
+<!ENTITY editpastequotation.accesskey "q">
+<!ENTITY editpastequotation.keybinding "v">
+<!ENTITY editStripQuotesCmd.label "Strip Quotes">
+<!ENTITY editRewrapCmd.label "Rewrap">
+<!ENTITY findCmd.label "Find and Replace…">
+<!ENTITY editfind.accesskey "f">
+<!ENTITY editfind.keybinding "f">
+<!ENTITY editfind.keybinding2 "VK_F19">
+<!ENTITY findAgainCmd.label "Find Again">
+<!ENTITY editfindnext.accesskey "g">
+<!ENTITY editfindnext.keybinding "g">
+<!ENTITY editfindnext.keybinding2 "VK_F3">
+<!ENTITY findPrevCmd.label "Find Previous">
+<!ENTITY editfindprev.accesskey "v">
+<!ENTITY editfindprev.keybinding "g">
+<!ENTITY editfindprev.keybinding2 "VK_F3">
+<!ENTITY enableInlineSpellChecker.label "Spellcheck As You Type">
+<!ENTITY enableInlineSpellChecker.accesskey "S">
+<!ENTITY checkSpellingCmd.label "Check Spelling">
+<!ENTITY editcheckspelling.accesskey "h">
+<!ENTITY editcheckspelling.keybinding "k">
+<!ENTITY validateCmd.label "Validate HTML">
+<!ENTITY validate.accesskey "v">
+<!ENTITY checkLinksCmd.label "Check Links">
+
+<!-- View menu items -->
+<!ENTITY viewPageSource.label "Page Source">
+<!ENTITY viewpagesource.accesskey "s">
+<!ENTITY viewParagraphMarks.label "Paragraph Marks">
+<!ENTITY viewparagraphmarks.accesskey "p">
+
+<!-- Insert menu items -->
+<!ENTITY insertMenu.label "Insert">
+<!ENTITY insertmenu.accesskey "i">
+<!ENTITY insertLinkCmd.label "Link…">
+<!ENTITY insertlink.accesskey "l">
+<!ENTITY insertlink.keybinding "l">
+<!ENTITY insertAnchorCmd.label "Named Anchor…">
+<!ENTITY insertanchor.accesskey "A">
+<!ENTITY insertImageCmd.label "Image…">
+<!ENTITY insertimage.accesskey "i">
+<!ENTITY insertImageMapCmd.label "Image Map…">
+<!ENTITY insertHLineCmd.label "Horizontal Line">
+<!ENTITY inserthline.accesskey "o">
+<!ENTITY insertTableCmd.label "Table…">
+<!ENTITY inserttable.accesskey "t">
+<!ENTITY insertFormMenu.label "Form">
+<!ENTITY insertformmenu.accesskey "F">
+<!ENTITY insertHTMLCmd.label "HTML…">
+<!ENTITY insertHTMLCmd.accesskey "h">
+<!ENTITY insertCharsCmd.label "Characters and Symbols…">
+<!ENTITY insertchars.accesskey "C">
+<!ENTITY insertBreakCmd.label "Line Break">
+<!ENTITY insertbreak.accesskey "b">
+<!ENTITY insertBreakAllCmd.label "Break Below Image(s)">
+<!ENTITY insertbreakall.accesskey "k">
+
+<!-- Insert form menu items -->
+<!ENTITY insertFormCmd.label "Define Form…">
+<!ENTITY insertform.accesskey "D">
+<!ENTITY insertInputTagCmd.label "Form Field…">
+<!ENTITY insertinputtag.accesskey "e">
+<!ENTITY insertInputImageCmd.label "Form Image…">
+<!ENTITY insertinputimage.accesskey "I">
+<!ENTITY insertTextAreaCmd.label "Text Area…">
+<!ENTITY inserttextarea.accesskey "T">
+<!ENTITY insertSelectCmd.label "Selection List…">
+<!ENTITY insertselect.accesskey "S">
+<!ENTITY insertButtonCmd.label "Define Button…">
+<!ENTITY insertbutton.accesskey "B">
+<!ENTITY insertLabelCmd.label "Define Label">
+<!ENTITY insertlabel.accesskey "L">
+<!ENTITY insertFieldSetCmd.label "Define Field Set…">
+<!ENTITY insertfieldset.accesskey "F">
+<!ENTITY insertIsIndexCmd.label "Index Search">
+<!ENTITY insertisindex.accesskey "x">
+
+<!-- Used just in context popup. -->
+<!ENTITY spellCheckNoSuggestions.label "(No Suggestions Found)">
+<!ENTITY spellCheckIgnoreWord.label "Ignore Word">
+<!ENTITY spellCheckIgnoreWord.accesskey "I">
+<!ENTITY spellCheckAddToDictionary.label "Add to Dictionary">
+<!ENTITY spellCheckAddToDictionary.accesskey "n">
+<!ENTITY createLinkCmd.label "Create Link…">
+<!ENTITY createlink.accesskey "k">
+<!ENTITY editLinkCmd.label "Edit Link in New Composer">
+<!ENTITY editlink.accesskey "i">
+<!-- (Toplevel Edit menu uses utilityOverlay) -->
+<!ENTITY undoCmd.label "Undo">
+<!ENTITY undo.accesskey "u">
+<!ENTITY redoCmd.label "Redo">
+<!ENTITY redo.accesskey "r">
+<!ENTITY cutCmd.label "Cut">
+<!ENTITY cut.accesskey "t">
+<!ENTITY copyCmd.label "Copy">
+<!ENTITY copy.accesskey "c">
+<!ENTITY pasteCmd.label "Paste">
+<!ENTITY paste.accesskey "p">
+<!ENTITY deleteCmd.label "Delete">
+<!ENTITY delete.accesskey "d">
+<!ENTITY clearCmd.label "Clear">
+<!ENTITY clear.accesskey "l">
+<!ENTITY selectAllCmd.label "Select All">
+<!ENTITY selectall.accesskey "a">
+
+<!-- Font Face SubMenu -->
+<!ENTITY FontFaceSelect.tooltip "Choose a font">
+<!ENTITY fontfaceMenu.label "Font">
+<!ENTITY formatfontmenu.accesskey "f">
+<!ENTITY fontVarWidth.label "Variable Width">
+<!ENTITY fontvarwidth.accesskey "v">
+<!ENTITY fontFixedWidth.label "Fixed Width">
+<!ENTITY fontfixedwidth.accesskey "x">
+<!ENTITY formatfontfixed.keybinding "t">
+<!ENTITY fontHelveticaFont.label "Helvetica, Arial">
+<!ENTITY fonthelvetica.accesskey "l">
+<!ENTITY fontTimes.label "Times">
+<!ENTITY fonttimes.accesskey "t">
+<!ENTITY fontCourier.label "Courier">
+<!ENTITY fontcourier.accesskey "c">
+<!ENTITY localfontfaceMenu.label "Local Fonts">
+<!ENTITY localfontmenu.accesskey "f">
+
+<!-- Font Size SubMenu -->
+<!ENTITY FontSizeSelect.tooltip "Choose a font size">
+<!ENTITY decreaseFontSize.label "Smaller">
+<!ENTITY decreasefontsize.accesskey "r">
+<!ENTITY decreaseFontSize.keybinding "-">
+<!ENTITY increaseFontSize.label "Larger">
+<!ENTITY increasefontsize.accesskey "g">
+<!ENTITY increaseFontSize.keybinding "+">
+<!ENTITY increaseFontSize.keybinding2 "="> <!-- + is above this key on many keyboards -->
+
+<!ENTITY fontsizeMenu.label "Size">
+<!ENTITY formatsizemenu.accesskey "z">
+<!ENTITY size-xx-smallCmd.label "xx-small">
+<!ENTITY size-xx-small.accesskey "a">
+<!ENTITY size-x-smallCmd.label "x-small">
+<!ENTITY size-x-small.accesskey "m">
+<!ENTITY size-smallCmd.label "small">
+<!ENTITY size-small.accesskey "s">
+<!ENTITY size-mediumCmd.label "medium">
+<!ENTITY size-medium.accesskey "d">
+<!ENTITY size-largeCmd.label "large">
+<!ENTITY size-large.accesskey "l">
+<!ENTITY size-x-largeCmd.label "x-large">
+<!ENTITY size-x-large.accesskey "x">
+<!ENTITY size-xx-largeCmd.label "xx-large">
+<!ENTITY size-xx-large.accesskey "e">
+
+<!-- Font Style SubMenu -->
+<!ENTITY fontStyleMenu.label "Text Style">
+<!ENTITY formatstylemenu.accesskey "s">
+<!ENTITY styleBoldCmd.label "Bold">
+<!ENTITY stylebold.accesskey "b">
+<!ENTITY stylebold.keybinding "b">
+<!ENTITY styleItalicCmd.label "Italic">
+<!ENTITY styleitalic.accesskey "I">
+<!ENTITY styleitalic.keybinding "i">
+<!ENTITY styleUnderlineCmd.label "Underline">
+<!ENTITY styleunderline.accesskey "u">
+<!ENTITY styleunderline.keybinding "u">
+<!ENTITY styleStrikeThruCmd.label "Strikethrough">
+<!ENTITY stylestrikethru.accesskey "k">
+<!ENTITY styleSuperscriptCmd.label "Superscript">
+<!ENTITY stylesuperscript.accesskey "p">
+<!ENTITY styleSubscriptCmd.label "Subscript">
+<!ENTITY stylesubscript.accesskey "S">
+<!ENTITY styleNonbreakingCmd.label "Nonbreaking">
+<!ENTITY stylenonbreaking.accesskey "N">
+<!ENTITY styleEm.label "Emphasis">
+<!ENTITY styleEm.accesskey "e">
+<!ENTITY styleStrong.label "Stronger Emphasis">
+<!ENTITY styleStrong.accesskey "t">
+<!ENTITY styleCite.label "Citation">
+<!ENTITY styleCite.accesskey "c">
+<!ENTITY styleAbbr.label "Abbreviation">
+<!ENTITY styleAbbr.accesskey "A">
+<!ENTITY styleAcronym.label "Acronym">
+<!ENTITY styleAcronym.accesskey "r">
+<!ENTITY styleCode.label "Code">
+<!ENTITY styleCode.accesskey "o">
+<!ENTITY styleSamp.label "Sample Output">
+<!ENTITY styleSamp.accesskey "m">
+<!ENTITY styleVar.label "Variable">
+<!ENTITY styleVar.accesskey "v">
+
+<!ENTITY formatFontColor.label "Text Color…">
+<!ENTITY formatfontcolor.accesskey "c">
+<!ENTITY tableOrCellColor.label "Table or Cell Background Color…">
+<!ENTITY tableOrCellColor.accesskey "B">
+
+<!ENTITY formatremovestyles.keybinding "y">
+<!ENTITY formatremovelinks.keybinding "k">
+<!ENTITY formatRemoveNamedAnchors.label "Remove Named Anchors">
+<!ENTITY formatRemoveNamedAnchors.accesskey "R">
+<!ENTITY formatremovenamedanchors.keybinding "a">
+
+<!ENTITY formatindent.keybinding "]">
+<!ENTITY formatoutdent.keybinding "[">
+<!ENTITY paragraphMenu.label "Paragraph">
+<!ENTITY formatparagraphmenu.accesskey "P">
+<!ENTITY paragraphParagraphCmd.label "Paragraph">  
+<!ENTITY paragraphparagraph.accesskey "P">
+<!ENTITY heading1Cmd.label "Heading 1">
+<!ENTITY heading1.accesskey "1">
+<!ENTITY heading2Cmd.label "Heading 2">
+<!ENTITY heading2.accesskey "2">
+<!ENTITY heading3Cmd.label "Heading 3">
+<!ENTITY heading3.accesskey "3">
+<!ENTITY heading4Cmd.label "Heading 4">
+<!ENTITY heading4.accesskey "4">
+<!ENTITY heading5Cmd.label "Heading 5">
+<!ENTITY heading5.accesskey "5">
+<!ENTITY heading6Cmd.label "Heading 6">
+<!ENTITY heading6.accesskey "6">
+<!ENTITY paragraphAddressCmd.label "Address">
+<!ENTITY paragraphaddress.accesskey "a">
+<!ENTITY paragraphPreformatCmd.label "Preformat">
+<!ENTITY paragraphpreformat.accesskey "f">
+<!ENTITY paragraphBlockquoteCmd.label "Blockquote">
+<!ENTITY paragraphblockquote.accesskey "b">
+
+<!-- List menu items -->
+<!ENTITY formatlistMenu.label "List">
+<!ENTITY formatlistmenu.accesskey "l">
+<!ENTITY noneCmd.label "None">
+<!ENTITY none.accesskey "N">
+<!ENTITY listBulletCmd.label "Bulleted">
+<!ENTITY listbullet.accesskey "b">
+<!ENTITY listNumberedCmd.label "Numbered">
+<!ENTITY listnumbered.accesskey "m">
+<!ENTITY listTermCmd.label "Term">
+<!ENTITY listterm.accesskey "t">
+<!ENTITY listDefinitionCmd.label "Definition">
+<!ENTITY listdefinition.accesskey "d">
+<!ENTITY listProps.label "List Properties…">
+<!ENTITY listprops.accesskey "l">
+
+<!ENTITY ParagraphSelect.tooltip "Choose a paragraph format">
+<!-- Shared in Paragraph, and Toolbar menulist -->
+<!ENTITY bodyTextCmd.label "Body Text">
+<!ENTITY bodytext.accesskey "T">
+<!-- isn't used in menu now, but may be added in future -->
+<!ENTITY advancedPropertiesCmd.label "Advanced Properties">
+<!ENTITY advancedproperties.accesskey "v">
+
+<!ENTITY NormalAbbr.label "Text">
+<!ENTITY ParagraphAbbr.label "P">  
+<!ENTITY Heading1Abbr.label "H1">
+<!ENTITY Heading2Abbr.label "H2">
+<!ENTITY Heading3Abbr.label "H3">
+<!ENTITY Heading4Abbr.label "H4">
+<!ENTITY Heading5Abbr.label "H5">
+<!ENTITY Heading6Abbr.label "H6">
+<!ENTITY BlockquoteAbbr.label "BQ">
+<!ENTITY AddressAbbr.label "Addr.">
+<!ENTITY PreformatAbbr.label "Pre.">
+
+<!-- Style Sheet submenu NOT IMPLEMENTED -->
+<!ENTITY stylesheetMenu.label "Apply Style Sheet">
+<!ENTITY formatstylesheetmenu.accesskey "y">
+
+<!-- Align menu items -->
+<!ENTITY alignMenu.label "Align">
+<!ENTITY formatalignmenu.accesskey "a">
+<!ENTITY alignLeft.label "Left">
+<!ENTITY alignleft.accesskey "l">
+<!ENTITY alignLeft.tooltip "Align Left">
+<!ENTITY alignCenter.label "Center">
+<!ENTITY aligncenter.accesskey "c">
+<!ENTITY alignCenter.tooltip "Align Center">
+<!ENTITY alignRight.label "Right">
+<!ENTITY alignright.accesskey "r">
+<!ENTITY alignRight.tooltip "Align Right">
+<!ENTITY alignJustify.label "Justify">
+<!ENTITY alignjustify.accesskey "j">
+<!ENTITY alignJustify.tooltip "Align Justified">
+
+<!-- Layer toolbar items -->
+<!ENTITY layer.tooltip "Layer">
+<!ENTITY layerSendToBack.tooltip "Send to Back">
+<!ENTITY layerBringToFront.tooltip "Bring to Front">
+
+<!ENTITY increaseIndent.label "Increase Indent">
+<!ENTITY increaseindent.accesskey "i">
+<!ENTITY increaseindentkb "=">
+<!ENTITY decreaseIndent.label "Decrease Indent">
+<!ENTITY decreaseindent.accesskey "D">
+<!ENTITY decreaseindentkb "-">
+
+<!ENTITY grid.label "Positioning grid">
+<!ENTITY grid.accesskey "t">
+
+<!ENTITY pageProperties.label "Page Title and Properties…">
+<!ENTITY pageproperties.accesskey "g">
+<!ENTITY colorsAndBackground.label "Page Colors and Background…">
+<!ENTITY colorsandbackground.accesskey "u">
+
+<!-- Table Menu -->
+<!ENTITY tableMenu.label "Table">
+<!ENTITY tablemenu.accesskey "b">
+<!-- Select Submenu -->
+<!ENTITY tableSelectMenu.label "Select">
+<!ENTITY tableselectmenu.accesskey "s">
+
+<!ENTITY tableSelectMenu2.label "Table Select">
+<!ENTITY tableInsertMenu2.label "Table Insert">
+<!ENTITY tableDeleteMenu2.label "Table Delete">
+
+<!-- Insert SubMenu -->
+<!ENTITY tableInsertMenu.label "Insert">
+<!ENTITY tableinsertmenu.accesskey "i">
+<!ENTITY tableTable.label "Table">
+<!ENTITY tabletable.accesskey "t">
+<!ENTITY tableRow.label "Row">
+<!ENTITY tableRows.label "Row(s)">
+<!ENTITY tablerow.accesskey "r">
+<!ENTITY tableRowAbove.label "Row Above">
+<!-- uses tablerow.accesskey -->
+<!ENTITY tableRowBelow.label "Row Below">
+<!ENTITY tablerowbelow.accesskey "b">
+<!ENTITY tableColumn.label "Column">
+<!ENTITY tableColumns.label "Column(s)">
+<!ENTITY tablecolumn.accesskey "o">
+<!ENTITY tableColumnBefore.label "Column Before">
+<!-- uses tablecolumn.accesskey -->
+<!ENTITY tableColumnAfter.label "Column After">
+<!ENTITY tablecolumnafter.accesskey "a">
+<!ENTITY tableCell.label "Cell">
+<!ENTITY tableCells.label "Cell(s)">
+<!ENTITY tablecell.accesskey "c">
+<!ENTITY tableCellContents.label "Cell Contents">
+<!ENTITY tablecellcontents.accesskey "n">
+<!ENTITY tableAllCells.label "All Cells">
+<!ENTITY tableCellBefore.label "Cell Before">
+<!ENTITY tableallcells.accesskey "a">
+<!-- uses tablecell.accesskey -->
+<!ENTITY tableCellAfter.label "Cell After">
+<!ENTITY tablecellafter.accesskey "f">
+<!-- Delete SubMenu -->
+<!ENTITY tableDeleteMenu.label "Delete">
+<!ENTITY tabledeletemenu.accesskey "D">
+
+<!ENTITY tableFix.label "Fix Table Layout">
+<!ENTITY tablefix.accesskey "f">
+<!-- text for "Join Cells" is in editor.properties 
+     ("JoinSelectedCells" and "JoinCellToRight")
+     the access key must exist in both of those strings
+     But value must be set here for accesskey to draw properly
+-->
+<!ENTITY tableJoinCells.label "j">
+<!ENTITY tablejoincells.accesskey "j">
+<!ENTITY tableSplitCell.label "Split Cell">
+<!ENTITY tablesplitcell.accesskey "c">
+<!ENTITY convertToTable.label "Create Table from Selection">
+<!ENTITY converttotable.accesskey "r">
+<!ENTITY tableProperties.label "Table Properties…">
+<!ENTITY tableProperties.accesskey "o">
+
+<!-- Tools menu -->
+<!ENTITY toolsmenu.accesskey "l">
+<!ENTITY toolbrowser.accesskey "b">
+<!ENTITY toolplaineditor.accesskey "p">
+<!ENTITY toolsetfocus.accesskey "f">
+
+<!-- Toolbar-only items -->
+<!ENTITY menuBar.tooltip "Menu Bar">
+<!ENTITY compositionToolbar.tooltip "Composition Toolbar">
+<!ENTITY formatToolbar.tooltip "Formatting Toolbar">
+<!ENTITY newToolbarCmd.tooltip "Create a new Composer page">
+<!ENTITY openToolbarCmd.label "Open">
+<!ENTITY openToolbarCmd.tooltip "Open a local file">
+<!ENTITY saveToolbarCmd.tooltip "Save file to a local location">
+<!ENTITY publishToolbarCmd.tooltip "Upload file to a remote location">
+<!ENTITY previewToolbarCmd.label "Browse">
+<!ENTITY previewToolbarCmd.tooltip "Load this page in the browser">
+<!ENTITY printToolbarCmd.label "Print">
+<!ENTITY printToolbarCmd.tooltip "Print this page">
+<!ENTITY findToolbarCmd.label "Find">
+<!ENTITY findToolbarCmd.tooltip "Find text in page">
+<!ENTITY spellToolbarCmd.label "Spell">
+<!ENTITY spellToolbarCmd.tooltip "Check spelling of selection or entire page">
+<!ENTITY imageToolbarCmd.label "Image">
+<!ENTITY imageToolbarCmd.tooltip "Insert new image or edit selected image's properties">
+<!ENTITY hruleToolbarCmd.label "H.Line">
+<!ENTITY hruleToolbarCmd.tooltip "Insert horizontal line or edit selected line's properties">
+<!ENTITY tableToolbarCmd.label "Table">
+<!ENTITY tableToolbarCmd.tooltip "Insert new table or edit selected table's properties">
+<!ENTITY linkToolbarCmd.label "Link">
+<!ENTITY linkToolbarCmd.tooltip "Insert new link or edit selected link's properties">
+<!ENTITY anchorToolbarCmd.label "Anchor">
+<!ENTITY anchorToolbarCmd.tooltip "Insert new named anchor or edit selected anchor's properties">
+<!ENTITY textColorCaption.label "Text Color">
+<!ENTITY TextColorButton.tooltip "Choose color for text">
+<!ENTITY BackgroundColorButton.tooltip "Choose color for background">
+<!ENTITY throbber.tooltip "Go to the &vendorShortName; home page">
+<!ENTITY HighlightColorButton.tooltip "Choose highlight color for text">
+
+<!-- Editor toolbar -->
+<!ENTITY decreaseFontSizeToolbarCmd.tooltip "Smaller font size">
+<!ENTITY increaseFontSizeToolbarCmd.tooltip "Larger font size">
+<!ENTITY boldToolbarCmd.tooltip "Bold">
+<!ENTITY italicToolbarCmd.tooltip "Italic">
+<!ENTITY underlineToolbarCmd.tooltip "Underline">
+<!ENTITY bulletListToolbarCmd.tooltip "Apply or remove bulleted list">
+<!ENTITY numberListToolbarCmd.tooltip "Apply or remove numbered list">
+<!ENTITY outdentToolbarCmd.tooltip "Outdent text (move left)">
+<!ENTITY indentToolbarCmd.tooltip "Indent text (move right)">
+<!ENTITY AlignPopupButton.tooltip "Choose text alignment">
+<!ENTITY InsertPopupButton.tooltip "Insert a Link, Anchor, Image, Horizontal Line, or Table">
+<!ENTITY alignLeftButton.tooltip "Align text along left margin">
+<!ENTITY alignCenterButton.tooltip "Align text centered">
+<!ENTITY alignRightButton.tooltip "Align text along right margin">
+<!ENTITY alignjustifyButton.tooltip "Align text along left and right margins">
+
+<!-- Formatting toolbar not used, but may be in future -->
+<!ENTITY formatToolbar.boldChar "B">
+<!ENTITY formatToolbar.italicChar "I">
+<!ENTITY formatToolbar.underlineChar "U">
+
+<!-- Used with color pickers in Format toolbar and Format Menu -->
+<!ENTITY colorPicker.default.label "Reader's default color">
+<!ENTITY colorPicker.default.accesskey "r">
+<!ENTITY colorLabel.label "Color:">
+<!ENTITY ok.label "OK">
+
+<!-- Display Mode toolbar and View menu items -->
+<!ENTITY NormalModeTab.label "Normal">
+<!ENTITY NormalMode.label "Normal Edit Mode">
+<!ENTITY NormalMode.accesskey "n">
+<!ENTITY NormalMode.tooltip "Show table borders and named anchors">
+<!ENTITY AllTagsMode.label "HTML Tags">
+<!ENTITY AllTagsMode.accesskey "A">
+<!ENTITY AllTagsMode.tooltip "Display icons for all HTML tags">
+
+<!ENTITY HTMLSourceMode.label "HTML Source">
+<!-- Toolbar has an image with "HTML" text, so don't include it in the string -->
+<!ENTITY SourceMode.label "Source">
+<!ENTITY HTMLSourceMode.accesskey "h">
+<!ENTITY HTMLSourceMode.tooltip "Edit HTML source">
+<!ENTITY PreviewMode.label "Preview">
+<!ENTITY PreviewMode.accesskey "p">
+<!ENTITY PreviewMode.tooltip "Display as WYSIWYG (as in the browser)">
+
+<!-- LOCALIZATION NOTE: Do NOT translate text for 'SourceTabDirection'
+     Use latin "ltr" if you want the <html> image to left of the 
+     'SourceMode.label' text defined above,
+     or use latin "rtl" if you want this image to the right of text
+     This is the value of the HTML 'dir' attribute
+-->
+<!ENTITY SourceTabDirection "ltr">
+
+<!-- Structure Toolbar Context Menu items -->
+<!ENTITY structSelect.label         "Select">
+<!ENTITY structSelect.accesskey     "s">
+<!ENTITY structRemoveTag.label      "Remove tag">
+<!ENTITY structRemoveTag.accesskey  "r">
+<!ENTITY structChangeTag.label      "Change tag">
+<!ENTITY structChangeTag.accesskey  "c">
+
+<!-- TOC manipulation -->
+<!ENTITY insertTOC.label          "Insert">
+<!ENTITY insertTOC.accesskey      "i">
+<!ENTITY updateTOC.label          "Update">
+<!ENTITY updateTOC.accesskey      "u">
+<!ENTITY removeTOC.label          "Remove">
+<!ENTITY removeTOC.accesskey      "r">
+<!ENTITY tocMenu.label            "Table of Contents…">
+<!ENTITY tocMenu.accesskey        "b">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/composer/editorPrefsOverlay.dtd
@@ -0,0 +1,9 @@
+
+<!--LOCALIZATION NOTE (editorCheck.label): DONT_TRANSLATE -->
+<!ENTITY editorCheck.label "Composer">
+<!ENTITY editorCheck.accesskey "c">
+
+<!ENTITY compose.label "Composer">
+<!ENTITY editing.label "New Page Settings">
+<!ENTITY toolbars.label "Toolbars">
+<!ENTITY publish.label "Publishing">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/composer/editorSmileyOverlay.dtd
@@ -0,0 +1,91 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Editor Smiley Overlay.
+   -
+   - The Initial Developer of the Original Code is
+   - Neil Rashbrook.
+   - Portions created by the Initial Developer are Copyright (C) 2003
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -    Neil Rashbrook <neil@parkwaycc.co.uk>
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either the GNU General Public License Version 2 or later (the "GPL"), or
+   - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the LGPL or the GPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!-- Smiley Menu items -->
+<!ENTITY insertSmiley.label "Smiley">
+<!ENTITY insertSmiley.accesskey "S">
+
+<!ENTITY smiley1Cmd.label "Smile">
+<!ENTITY smiley1Cmd.accesskey "S">
+<!ENTITY smiley1Cmd.tooltip "Insert a smiley face">
+<!ENTITY smiley2Cmd.label "Frown">
+<!ENTITY smiley2Cmd.accesskey "F">
+<!ENTITY smiley2Cmd.tooltip "Insert a frown face">
+<!ENTITY smiley3Cmd.label "Wink">
+<!ENTITY smiley3Cmd.accesskey "W">
+<!ENTITY smiley3Cmd.tooltip "Insert a wink face">
+<!ENTITY smiley4Cmd.label "Tongue-out">
+<!ENTITY smiley4Cmd.accesskey "T">
+<!ENTITY smiley4Cmd.tooltip "Insert a tongue-out face">
+<!ENTITY smiley5Cmd.label "Laughing">
+<!ENTITY smiley5Cmd.accesskey "L">
+<!ENTITY smiley5Cmd.tooltip "Insert a laughing face">
+<!ENTITY smiley6Cmd.label "Embarrassed">
+<!ENTITY smiley6Cmd.accesskey "E">
+<!ENTITY smiley6Cmd.tooltip "Insert an embarrassed face">
+<!ENTITY smiley7Cmd.label "Undecided">
+<!ENTITY smiley7Cmd.accesskey "U">
+<!ENTITY smiley7Cmd.tooltip "Insert an undecided face">
+<!ENTITY smiley8Cmd.label "Surprise">
+<!ENTITY smiley8Cmd.accesskey "p">
+<!ENTITY smiley8Cmd.tooltip "Insert a surprised face">
+<!ENTITY smiley9Cmd.label "Kiss">
+<!ENTITY smiley9Cmd.accesskey "K">
+<!ENTITY smiley9Cmd.tooltip "Insert a kiss face">
+<!ENTITY smiley10Cmd.label "Yell">
+<!ENTITY smiley10Cmd.accesskey "Y">
+<!ENTITY smiley10Cmd.tooltip "Insert a yelling face">
+<!ENTITY smiley11Cmd.label "Cool">
+<!ENTITY smiley11Cmd.accesskey "C">
+<!ENTITY smiley11Cmd.tooltip "Insert a cool face">
+<!ENTITY smiley12Cmd.label "Money-Mouth">
+<!ENTITY smiley12Cmd.accesskey "M">
+<!ENTITY smiley12Cmd.tooltip "Insert a money-mouth face">
+<!ENTITY smiley13Cmd.label "Foot-in-Mouth">
+<!ENTITY smiley13Cmd.accesskey "o">
+<!ENTITY smiley13Cmd.tooltip "Insert a foot-in-mouth face">
+<!ENTITY smiley14Cmd.label "Innocent">
+<!ENTITY smiley14Cmd.accesskey "I">
+<!ENTITY smiley14Cmd.tooltip "Insert an innocent face">
+<!ENTITY smiley15Cmd.label "Cry">
+<!ENTITY smiley15Cmd.accesskey "r">
+<!ENTITY smiley15Cmd.tooltip "Insert a crying face">
+<!ENTITY smiley16Cmd.label "Lips-are-Sealed">
+<!ENTITY smiley16Cmd.accesskey "a">
+<!ENTITY smiley16Cmd.tooltip "Insert a lips-are-sealed face">
+<!ENTITY SmileButton.tooltip "Insert a smiley face">
+
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/composer/pref-composer.dtd
@@ -0,0 +1,39 @@
+<!-- extracted from content/pref-composer.xul -->
+
+<!--LOCALIZATION NOTE : FILE 'Composer' prefs dialog. Similar to Communcator 4.x Document Properties/Colors and Background -->
+
+<!--LOCALIZATION NOTE (pref.composer.title): DONT_TRANSLATE -->
+<!ENTITY  pref.composer.title           "Composer">
+
+<!ENTITY  saving                        "Saving">
+<!ENTITY  AutoSaveCheck                 "Automatically save every">
+<!ENTITY  minText                       "minutes">
+
+<!ENTITY  exterLegend.label             "External Editors">
+<!ENTITY  htmlSource                    "HTML Source:">
+<!ENTITY  imageeditor                   "Images:">
+<!ENTITY  chooseButton.label            "Choose">
+
+<!ENTITY  recentFiles.title             "Recent Pages Menu">
+<!ENTITY  documentsInMenu.label         "Maximum number of pages listed:">
+<!ENTITY  documentsInMenu.accesskey     "n">
+
+<!ENTITY  savingFiles.title             "When Saving or Publishing Pages">
+<!ENTITY  preserveExisting.label        "Preserve original source formatting">
+<!ENTITY  preserveExisting.accesskey    "P">
+<!ENTITY  preserveExisting.tooltip      "Preserves line breaks and page's original formatting">
+<!ENTITY  saveAssociatedFiles.label     "Save images and other associated files when saving pages">
+<!ENTITY  saveAssociatedFiles.accesskey "S">
+<!ENTITY  showPublishDialog.label       "Always show Publish dialog when publishing pages">
+<!ENTITY  showPublishDialog.accesskey   "A">
+
+<!ENTITY  composerEditing.label         "Editing">
+<!ENTITY  spellCheckInline.label        "Check spelling as you type">
+<!ENTITY  spellCheckInline.accesskey    "C">
+<!ENTITY  maintainStructure.label       "Maintain table layout when inserting or deleting cells">
+<!ENTITY  maintainStructure.tooltip     "Preserves table's rectangular shape by automatically adding cells after inserting or deleting cells">
+<!ENTITY  maintainStructure.accesskey   "M">
+<!ENTITY  useCSS.label                  "Use CSS styles instead of HTML elements and attributes">
+<!ENTITY  useCSS.accesskey              "U">
+<!ENTITY  crInPCreatesNewP.label        "Return in a paragraph always creates a new paragraph">
+<!ENTITY  crInPCreatesNewP.accesskey    "R">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/composer/pref-editing.dtd
@@ -0,0 +1,28 @@
+<!ENTITY  pref.editing.title        "New Page Settings">
+
+<!ENTITY  authorName.label          "Author:">
+<!ENTITY  authorName.accesskey      "u">
+<!ENTITY  pageColorHeader           "Default Page Appearance">
+
+<!ENTITY defaultColorsRadio.label   "Reader's default colors (Don't set colors in page)">
+<!ENTITY defaultColors.accesskey    "d">
+<!ENTITY customColorsRadio.label    "Use custom colors:">
+<!ENTITY customColors.accesskey     "c">
+
+<!ENTITY normalText.label           "Normal text">
+<!ENTITY normalText.accesskey       "N">
+<!ENTITY linkText.label             "Link text">
+<!ENTITY linkText.accesskey         "L">
+<!ENTITY activeLinkText.label       "Active link text">
+<!ENTITY activeLinkText.accesskey   "A">
+<!ENTITY visitedLinkText.label      "Visited link text">
+<!ENTITY visitedLinkText.accesskey  "V">
+<!ENTITY background.label           "Background:">
+<!ENTITY background.accesskey       "B">
+<!ENTITY colon.character            ":">
+
+<!ENTITY backgroundImage.label      "Background image:">
+<!ENTITY backgroundImage.accesskey  "m">
+<!ENTITY chooseFile.label           "Choose File…">
+<!ENTITY chooseFile.accesskey       "o">
+
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/composer/pref-toolbars.dtd
@@ -0,0 +1,71 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Editor Toolbar Preferences.
+   -
+   - The Initial Developer of the Original Code is
+   - Neil Rashbrook.
+   - Portions created by the Initial Developer are Copyright (C) 2003
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s): Neil Rashbrook <neil@parkwaycc.co.uk>
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either the GNU General Public License Version 2 or later (the "GPL"), or
+   - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the LGPL or the GPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!ENTITY pref.toolbars.title    "Toolbars">
+
+<!ENTITY composition.caption    "Show these buttons in the Composition Toolbar:">
+
+<!ENTITY new.label              "New">
+<!ENTITY open.label             "Open">
+<!ENTITY save.label             "Save">
+<!ENTITY publish.label          "Publish">
+<!ENTITY preview.label          "Browse">
+<!ENTITY cut.label              "Cut">
+<!ENTITY copy.label             "Copy">
+<!ENTITY paste.label            "Paste">
+<!ENTITY print.label            "Print">
+<!ENTITY find.label             "Find">
+<!ENTITY image.label            "Image">
+<!ENTITY hline.label            "H. Line">
+<!ENTITY table.label            "Table">
+<!ENTITY link.label             "Link">
+<!ENTITY anchor.label           "Anchor">
+
+<!ENTITY formatting.caption     "Show these buttons in the Formatting Toolbar:">
+
+<!ENTITY smaller.label          "Smaller">
+<!ENTITY larger.label           "Larger">
+<!ENTITY bold.label             "Bold">
+<!ENTITY bullets.label          "Bullets">
+<!ENTITY numbers.label          "Numbers">
+<!ENTITY italic.label           "Italic">
+<!ENTITY outdent.label          "Outdent">
+<!ENTITY indent.label           "Indent">
+<!ENTITY underline.label        "Underline">
+
+<!ENTITY absolutePosition.label "Absolute positioning">
+<!ENTITY decreaseZIndex.label   "Send to back">
+<!ENTITY increaseZIndex.label   "Bring to front">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EdAdvancedEdit.dtd
@@ -0,0 +1,52 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -   Ben Goodger
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!ENTITY WindowTitle.label              "Advanced Property Editor">
+<!ENTITY AttName.label                  "Attribute: ">
+<!ENTITY AttValue.label                 "Value: ">
+<!ENTITY PropertyName.label             "Property: ">
+<!ENTITY currentattributesfor.label     "Current attributes for: ">
+<!ENTITY tree.attributeHeader.label     "Attribute">
+<!ENTITY tree.propertyHeader.label      "Property">
+<!ENTITY tree.valueHeader.label         "Value">
+<!ENTITY tabHTML.label                  "HTML Attributes">
+<!ENTITY tabCSS.label                   "Inline Style">
+<!ENTITY tabJSE.label                   "JavaScript Events">
+
+<!ENTITY editAttribute.label    "Click on an item above to edit its value">
+<!ENTITY removeAttribute.label  "Remove">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EdColorPicker.dtd
@@ -0,0 +1,55 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-2000
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!ENTITY windowTitle.label "Color">
+<!ENTITY lastPickedColor.label "Last-picked color">
+<!ENTITY lastPickedColor.accessKey "L">
+<!ENTITY setColor1.label "Click on a color or">
+<!ENTITY setColor2.label "enter an HTML color string">
+<!ENTITY setColor2.accessKey "H">
+<!ENTITY setColorExample.label "(e.g.: &quot;#0000ff&quot; or &quot;blue&quot;):">
+<!ENTITY default.label "Default">
+<!ENTITY default.accessKey "D">
+<!ENTITY palette.label "Palette:">
+<!ENTITY standardPalette.label "Standard">
+<!ENTITY webPalette.label "All web colors">
+<!ENTITY background.label "Background for:">
+<!ENTITY background.accessKey "B">
+<!ENTITY table.label "Table">
+<!ENTITY table.accessKey "T">
+<!ENTITY cell.label "Cell(s)">
+<!ENTITY cell.accessKey "C">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EdConvertToTable.dtd
@@ -0,0 +1,48 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+
+<!-- Window title -->
+<!ENTITY windowTitle.label "Convert To Table">
+<!ENTITY instructions1.label   "Composer creates a new table row for each paragraph in the selection.">
+<!ENTITY instructions2.label   "Choose the character used to separate the selection into columns:">
+<!ENTITY commaRadio.label      "Comma">
+<!ENTITY spaceRadio.label      "Space">
+<!ENTITY otherRadio.label      "Other Character:">
+<!ENTITY deleteCharCheck.label "Delete separator character">
+<!ENTITY collapseSpaces.label  "Ignore extra spaces">
+<!ENTITY collapseSpaces.tooltip "Convert adjacent spaces to one separator">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EdDialogOverlay.dtd
@@ -0,0 +1,51 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-2000
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!ENTITY AdvancedEditButton.label "Advanced Edit…">
+<!ENTITY AdvancedEditButton.accessKey "E">
+<!ENTITY AdvancedEditButton.tooltip "Add or modify HTML attributes, style attributes, and JavaScript">
+<!ENTITY chooseFileButton.label "Choose File...">
+<!ENTITY chooseFileButton.accessKey "F">
+<!ENTITY chooseFileLinkButton.label "Choose File...">
+<!ENTITY chooseFileLinkButton.accessKey "o">
+<!ENTITY makeUrlRelative.label "URL is relative to page location">
+<!ENTITY makeUrlRelative.accessKey "r">
+<!ENTITY makeUrlRelative.tooltip "Change between relative and absolute URL. You must first save the page to change this.">
+
+<!-- Shared by Link and Image dialogs -->
+<!ENTITY LinkURLEditField.label "Enter a web page location, a local file, or select a Named Anchor or Heading from the popup list:">
+<!ENTITY LinkURLEditField.accessKey "L">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EdLinkChecker.dtd
@@ -0,0 +1,46 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -   Charles Manxke (cmanske@netscape.com)
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!-- Window title -->
+<!ENTITY windowTitle.label     "Check Image and Link Locations">
+<!ENTITY urlsNotFound.label    "The following image or link locations were not found:">
+<!ENTITY notFoundKey.label     "(&quot;X&quot; = file not found, &quot;?&quot; = timed-out attempting to connect.)">
+<!ENTITY changeUrlButton.label "Change Location of Selected Item">
+<!ENTITY succeeded.label       "Succeeded">
+<!ENTITY failed.label          "Failed">
+<!ENTITY closeButton.label     "Close">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EdNamedAnchorProperties.dtd
@@ -0,0 +1,43 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-2000
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!ENTITY windowTitle.label "Named Anchor Properties">
+<!ENTITY anchorNameEditField.label "Anchor Name:">
+<!ENTITY anchorNameEditField.accessKey "N">
+<!ENTITY nameInput.tooltip "Enter a unique name for this named anchor (target)">
+
+
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EditConflict.dtd
@@ -0,0 +1,43 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-2000
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!-- Window title -->
+<!ENTITY windowTitle.label "Select Edit Changes">
+<!ENTITY conflictWarning.label "This page has been modified by another program, but you also have unsaved changes in Composer.">
+<!ENTITY conflictResolve.label "Select which version to keep:">
+<!ENTITY keepCurrentPageButton.label "Keep current page changes">
+<!ENTITY useOtherPageButton.label "Replace current page with other changes">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EditorButtonProperties.dtd
@@ -0,0 +1,59 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Button Properties Dialog.
+   -
+   - The Initial Developer of the Original Code is
+   - Neil Rashbrook.
+   - Portions created by the Initial Developer are Copyright (C) 2001
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s): Neil Rashbrook <neil@parkwaycc.co.uk>
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either the GNU General Public License Version 2 or later (the "GPL"), or
+   - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the LGPL or the GPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!ENTITY windowTitle.label "Button Properties">
+
+<!ENTITY Settings.label "Settings">
+
+<!ENTITY ButtonType.label "Type">
+<!ENTITY ButtonType.accesskey "T">
+<!ENTITY submit.value "Submit">
+<!ENTITY reset.value "Reset">
+<!ENTITY button.value "Button">
+
+<!ENTITY ButtonName.label "Name:">
+<!ENTITY ButtonName.accesskey "N">
+<!ENTITY ButtonValue.label "Value:">
+<!ENTITY ButtonValue.accesskey "V">
+<!ENTITY tabIndex.label "Tab Index:">
+<!ENTITY tabIndex.accesskey "I">
+<!ENTITY ButtonDisabled.label "Disabled">
+<!ENTITY ButtonDisabled.accesskey "D">
+<!ENTITY AccessKey.label "Access Key:">
+<!ENTITY AccessKey.accesskey "K">
+
+<!ENTITY RemoveButton.label "Remove Button">
+<!ENTITY RemoveButton.accesskey "R">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EditorColorProperties.dtd
@@ -0,0 +1,61 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!-- Window title -->
+<!ENTITY windowTitle.label "Page Colors and Background">
+<!ENTITY pageColors.label "Page Colors">
+<!ENTITY defaultColorsRadio.label "Reader's default colors (Don't set colors in page)">
+<!ENTITY defaultColorsRadio.accessKey "D">
+<!ENTITY defaultColorsRadio.tooltip "Use the color settings from the viewer (reader's) browser only">
+<!ENTITY customColorsRadio.label "Use custom colors:">
+<!ENTITY customColorsRadio.accessKey "C">
+<!ENTITY customColorsRadio.tooltip "These color settings override the viewer's browser settings">
+
+<!ENTITY normalText.label "Normal text">
+<!ENTITY normalText.accessKey "N">
+<!ENTITY linkText.label "Link text">
+<!ENTITY linkText.accessKey "L">
+<!ENTITY activeLinkText.label "Active link text">
+<!ENTITY activeLinkText.accessKey "A">
+<!ENTITY visitedLinkText.label "Visited link text">
+<!ENTITY visitedLinkText.accessKey "V">
+<!ENTITY background.label "Background:">
+<!ENTITY background.accessKey "B">
+<!ENTITY colon.character ":">
+<!ENTITY backgroundImage.label "Background Image:">
+<!ENTITY backgroundImage.accessKey "m">
+<!ENTITY backgroundImage.tooltip "Use an image file as the background for your page">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EditorFieldSetProperties.dtd
@@ -0,0 +1,52 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Button Properties Dialog.
+   -
+   - The Initial Developer of the Original Code is
+   - Neil Rashbrook.
+   - Portions created by the Initial Developer are Copyright (C) 2001
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s): Neil Rashbrook <neil@parkwaycc.co.uk>
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either the GNU General Public License Version 2 or later (the "GPL"), or
+   - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the LGPL or the GPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!ENTITY windowTitle.label "Field Set Properties">
+
+<!ENTITY Legend.label "Legend">
+<!ENTITY Legend.accesskey "L">
+
+<!ENTITY EditLegendText.label "Edit Legend:">
+<!ENTITY EditLegendText.accesskey "T">
+<!ENTITY LegendAlign.label "Align Legend:">
+<!ENTITY LegendAlign.accesskey "A">
+<!ENTITY AlignDefault.label "Default">
+<!ENTITY AlignLeft.label "Left">
+<!ENTITY AlignCenter.label "Center">
+<!ENTITY AlignRight.label "Right">
+
+<!ENTITY RemoveFieldSet.label "Remove Field Set">
+<!ENTITY RemoveFieldSet.accesskey "R">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EditorFormProperties.dtd
@@ -0,0 +1,53 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Form Properties Dialog.
+   -
+   - The Initial Developer of the Original Code is
+   - Neil Rashbrook.
+   - Portions created by the Initial Developer are Copyright (C) 2001
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s): Neil Rashbrook <neil@parkwaycc.co.uk>
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either the GNU General Public License Version 2 or later (the "GPL"), or
+   - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the LGPL or the GPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!ENTITY windowTitle.label "Form Properties">
+
+<!ENTITY Settings.label "Settings">
+
+<!ENTITY FormName.label "Form Name:">
+<!ENTITY FormName.accesskey "N">
+<!ENTITY FormAction.label "Action URL:">
+<!ENTITY FormAction.accesskey "A">
+<!ENTITY FormMethod.label "Method:">
+<!ENTITY FormMethod.accesskey "M">
+<!ENTITY FormEncType.label "Encoding:">
+<!ENTITY FormEncType.accesskey "c">
+<!ENTITY FormTarget.label "Target Frame:">
+<!ENTITY FormTarget.accesskey "T">
+
+<!ENTITY RemoveForm.label "Remove Form">
+<!ENTITY RemoveForm.accesskey "R">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EditorHLineProperties.dtd
@@ -0,0 +1,60 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+
+<!-- Window title -->
+<!ENTITY windowTitle.label "Horizontal Line Properties">
+
+<!ENTITY dimensionsBox.label "Dimensions">
+<!ENTITY heightEditField.label "Height:">
+<!ENTITY heightEditField.accessKey "G">
+<!ENTITY widthEditField.label "Width:">
+<!ENTITY widthEditField.accessKey "W">
+<!ENTITY pixelsPopup.value "pixels">
+<!ENTITY alignmentBox.label "Alignment">
+<!ENTITY leftRadio.label "Left">
+<!ENTITY leftRadio.accessKey "L">
+<!ENTITY centerRadio.label "Center">
+<!ENTITY centerRadio.accessKey "C">
+<!ENTITY rightRadio.label "Right">
+<!ENTITY rightRadio.accessKey "R">
+
+<!ENTITY threeDShading.label "3-D Shading">
+<!ENTITY threeDShading.accessKey "S">
+<!ENTITY saveSettings.label "Use as Default">
+<!ENTITY saveSettings.accessKey "D">
+<!ENTITY saveSettings.tooltip "Save these settings to use when inserting new horizontal lines">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EditorImageMap.dtd
@@ -0,0 +1,104 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -   Dan Haddix (dan6992@hotmail.com)
+   -   Brian King (briano9@yahoo.com)
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!-- These strings are for use specifically in the editor's image map dialog. -->
+
+<!-- Window title -->
+<!ENTITY windowTitle.label "Image Map Editor">
+
+<!-- Menu Items -->
+<!-- File menu -->
+<!ENTITY mapfileMenu.label "File">
+<!ENTITY mapfilemenu.accesskey "f">
+<!ENTITY clearCmd.label "Clear">
+<!ENTITY mapfileclear.accesskey "a">
+<!ENTITY closeCmd.label "Close">
+<!ENTITY mapfileclose.accesskey "c">
+
+<!-- Edit menu -->
+<!ENTITY mapeditMenu.label "Edit">
+<!ENTITY mapeditmenu.accesskey "e">
+<!ENTITY cutCmd.label "Cut">
+<!ENTITY mapeditcut.accesskey "t">
+<!ENTITY copyCmd.label "Copy">
+<!ENTITY mapeditcopy.accesskey "c">
+<!ENTITY pasteCmd.label "Paste">
+<!ENTITY mapeditpaste.accesskey "p">
+<!ENTITY selectallCmd.label "Select All">
+<!ENTITY mapselectall.accesskey "s">
+<!ENTITY propsCmd.label "Hotspot Properties">
+<!ENTITY mapeditprops.accesskey "h">
+
+<!-- View menu -->
+<!ENTITY mapviewMenu.label "View">
+<!ENTITY mapviewmenu.accesskey "v">
+<!ENTITY showhideTbarCmd.label "Hide Toolbar">
+<!ENTITY mapviewtbar.accesskey "t">
+<!-- Scaling -->
+<!ENTITY mapviewScale.label "Scale">
+<!ENTITY mapviewscale.accesskey "S">
+<!ENTITY apercentCmd.label "100">
+<!ENTITY zoomone.accesskey "1">
+<!ENTITY bpercentCmd.label "200">
+<!ENTITY zoomtwo.accesskey "2">
+<!ENTITY cpercentCmd.label "400">
+<!ENTITY zoomthree.accesskey "4">
+<!-- end scaling-->
+<!ENTITY contrastCmd.label "Contrast">
+<!ENTITY contrast.accesskey "n">
+
+<!-- Help menu -->
+<!ENTITY maphelpMenu.label "Help">
+<!ENTITY maphelpmenu.accesskey "h">
+<!ENTITY aboutCmd.label "About">
+<!ENTITY about.accesskey "b">
+
+<!ENTITY zoominCmd.label "Zoom In">
+<!ENTITY zoomoutCmd.label "Zoom Out">
+<!ENTITY delSpotCmd.label "Delete Spot">
+
+<!-- Keys -->
+<!ENTITY clear.accesskey "d">
+<!ENTITY selectall.accesskey "a">
+<!ENTITY close.accesskey "l">
+<!ENTITY cut.accesskey "x">
+<!ENTITY copy.accesskey "c">
+<!ENTITY paste.accesskey "v">
+<!ENTITY props.accesskey "p">
+<!ENTITY tbar.accesskey "t">
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EditorImageMapHotSpot.dtd
@@ -0,0 +1,58 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-2000
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -   Dan Haddix (dan6992@hotmail.com)
+   -   Brian King (briano9@yahoo.com)
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!-- Window title -->
+
+<!ENTITY windowTitle.label "Hotspot Properties">
+
+<!ENTITY link.label				"Hotspot Link">
+<!ENTITY urlFieldset.label		"Hotspot URL:">
+<!ENTITY altFieldset.label		"Hotspot Alt Text:">
+<!ENTITY browseButton.label		"Browse…">
+<!ENTITY targetFieldset.label	"Target Setting">
+<!ENTITY target.label			"Hotspot Target">
+
+<!-- Targets -->
+<!ENTITY commonFieldset.label	"Common Targets:">
+<!ENTITY none.value				"(none)">
+<!ENTITY same.value				"Same Frame">
+<!ENTITY whole.value			"Whole Page">
+<!ENTITY new.value				"New Window">
+<!ENTITY parent.value			"Parent Frame">
+
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EditorImageProperties.dtd
@@ -0,0 +1,119 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-2000
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!-- These strings are for use specifically in the editor's image and form image dialogs. -->
+
+<!-- Window title -->
+<!ENTITY windowTitle.label "Image Properties">
+
+<!ENTITY pixelsPopup.value "pixels">
+<!ENTITY percentPopup.value "percent">
+
+<!-- These are in the Location tab panel -->
+<!ENTITY locationEditField.label "Image Location:">
+<!ENTITY locationEditField.accessKey "L">
+<!ENTITY locationEditField.tooltip "Type the image's filename or location">
+<!ENTITY title.label "Tooltip:">
+<!ENTITY title.accessKey "T">
+<!ENTITY title.tooltip "The html 'title' attribute that displays as a tooltip">
+<!ENTITY altText.label "Alternate text:">
+<!ENTITY altText.accessKey "A">
+<!ENTITY altTextEditField.tooltip "Type text to display in place of the image">
+<!ENTITY noAltText.label "Don't use alternate text">
+<!ENTITY noAltText.accessKey "D">
+
+<!ENTITY previewBox.label "Image Preview">
+<!ENTITY MoreFewerButton.tooltip "Display more or fewer properties to edit">
+
+<!-- These controls are in the Dimensions tab panel -->
+<!-- actualSize.label should be same as actualSizeRadio.label + ":" -->
+<!ENTITY actualSize.label "Actual Size:">
+<!ENTITY actualSizeRadio.label "Actual Size">
+<!ENTITY actualSizeRadio.accessKey "A">
+<!ENTITY actualSizeRadio.tooltip "Revert to the image's actual size">
+<!ENTITY customSizeRadio.label "Custom Size">
+<!ENTITY customSizeRadio.accessKey "S">
+<!ENTITY customSizeRadio.tooltip "Change the image's size as displayed in the page">
+<!ENTITY heightEditField.label "Height:">
+<!ENTITY heightEditField.accessKey "G">
+<!ENTITY widthEditField.label "Width:">
+<!ENTITY widthEditField.accessKey "W">
+<!ENTITY constrainCheckbox.label "Constrain">
+<!ENTITY constrainCheckbox.accessKey "C">
+<!ENTITY constrainCheckbox.tooltip "Maintain the image's aspect ratio">
+
+<!-- These controls are in the Image Map box of the expanded area -->
+<!ENTITY imagemapBox.label "Image Map">
+<!ENTITY removeImageMapButton.label "Remove">
+<!ENTITY removeImageMapButton.accessKey "R">
+<!ENTITY editImageMapButton.label "Edit…">
+<!ENTITY editImageMapButton.tooltip "Create clickable hotspots for this image">
+
+<!-- These are the options for image alignment -->
+<!ENTITY alignment.label "Align Text to Image">
+<!ENTITY bottomPopup.value "At the bottom">
+<!ENTITY topPopup.value "At the top">
+<!ENTITY centerPopup.value "In the center">
+<!ENTITY wrapRightPopup.value "Wrap to the right">
+<!ENTITY wrapLeftPopup.value "Wrap to the left">
+
+<!-- These controls are in the Spacing Box -->
+<!ENTITY spacingBox.label "Spacing">
+<!ENTITY spacingBox.tooltip "Type a number for the amount of space around image">
+<!ENTITY leftRightEditField.label "Left and Right:">
+<!ENTITY leftRightEditField.accessKey "L">
+<!ENTITY topBottomEditField.label "Top and Bottom:">
+<!ENTITY topBottomEditField.accessKey "T">
+<!ENTITY borderEditField.label "Solid Border:">
+<!ENTITY borderEditField.accessKey "B">
+
+<!-- These controls are in the Link Box -->
+<!ENTITY showImageLinkBorder.label "Show border around linked image">
+<!ENTITY showImageLinkBorder.accessKey "B">
+
+<!-- These controls may be added some day; currently not used -->
+<!ENTITY makePageBackgroundCheckbox.label "Make Page Background">
+<!ENTITY makePageBackgroundCheckbox.tooltip "Use image as background for your page">
+<!ENTITY editImageButton.label "Edit Image">
+<!ENTITY editImageButton.tooltip "Edit image file in another program">
+
+<!-- These tabs are currently used in the image input dialog -->
+<!ENTITY imageInputTab.label "Form">
+<!ENTITY imageLocationTab.label "Location">
+<!ENTITY imageDimensionsTab.label "Dimensions">
+<!ENTITY imageAppearanceTab.label "Appearance">
+<!ENTITY imageLinkTab.label "Link">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EditorInputProperties.dtd
@@ -0,0 +1,80 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Input Tag Properties Dialog.
+   -
+   - The Initial Developer of the Original Code is
+   - Neil Rashbrook.
+   - Portions created by the Initial Developer are Copyright (C) 2001
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s): Neil Rashbrook <neil@parkwaycc.co.uk>
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either the GNU General Public License Version 2 or later (the "GPL"), or
+   - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the LGPL or the GPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!ENTITY windowTitle.label "Form Field Properties">
+<!ENTITY windowTitleImage.label "Form Image Properties">
+
+<!ENTITY InputType.label "Field Type">
+<!ENTITY InputType.accesskey "T">
+<!ENTITY text.value "Text">
+<!ENTITY password.value "Password">
+<!ENTITY checkbox.value "Check Box">
+<!ENTITY radio.value "Radio Button">
+<!ENTITY submit.value "Submit Button">
+<!ENTITY reset.value "Reset Button">
+<!ENTITY file.value "File">
+<!ENTITY hidden.value "Hidden">
+<!ENTITY image.value "Image">
+<!ENTITY button.value "Button">
+
+<!ENTITY InputSettings.label "Field Settings">
+<!ENTITY InputName.label "Field Name:">
+<!ENTITY GroupName.label "Group Name:">
+<!ENTITY Name.accesskey "N">
+<!ENTITY InputValue.label "Field Value:">
+<!ENTITY InitialValue.label "Initial Value:">
+<!ENTITY Value.accesskey "V">
+<!ENTITY InputChecked.label "Initially Checked">
+<!ENTITY InputChecked.accesskey "C">
+<!ENTITY InputSelected.label "Initially Selected">
+<!ENTITY InputSelected.accesskey "S">
+<!ENTITY InputReadOnly.label "Read Only">
+<!ENTITY InputReadOnly.accesskey "R">
+<!ENTITY InputDisabled.label "Disabled">
+<!ENTITY InputDisabled.accesskey "D">
+<!ENTITY tabIndex.label "Tab Index:">
+<!ENTITY tabIndex.accesskey "I">
+<!ENTITY TextSize.label "Field Size:">
+<!ENTITY TextSize.accesskey "F">
+<!ENTITY TextLength.label "Maximum Length:">
+<!ENTITY TextLength.accesskey "L">
+<!ENTITY AccessKey.label "Access Key:">
+<!ENTITY AccessKey.accesskey "K">
+<!ENTITY Accept.label "Accept Types:">
+<!ENTITY Accept.accesskey "A">
+
+<!ENTITY ImageProperties.label "Image Properties…">
+<!ENTITY ImageProperties.accesskey "E">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EditorInsertChars.dtd
@@ -0,0 +1,52 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+
+<!-- Window title -->
+<!ENTITY windowTitle.label "Insert Character">
+<!ENTITY category.label "Category">
+<!ENTITY letter.label "Letter:">
+<!ENTITY letter.accessKey "L">
+<!ENTITY character.label "Character:">
+<!ENTITY character.accessKey "C">
+<!ENTITY accentUpper.label "Accent Uppercase">
+<!ENTITY accentLower.label "Accent Lowercase">
+<!ENTITY otherUpper.label "Other Uppercase">
+<!ENTITY otherLower.label "Other Lowercase">
+<!ENTITY commonSymbols.label "Common Symbols">
+<!ENTITY insertButton.label "Insert">
+<!ENTITY closeButton.label "Close">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EditorInsertSource.dtd
@@ -0,0 +1,48 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!-- Window title -->
+<!ENTITY windowTitle.label "Insert HTML">
+<!ENTITY sourceEditField.label "Enter HTML tags and text:">
+<!ENTITY example.label "Example: ">
+<!-- LOCALIZATION NOTE (exampleOpenTag.label): DONT_TRANSLATE: they are text for HTML tagnames: "<i>" and "</i>" -->
+<!ENTITY exampleOpenTag.label "&lt;i&gt;">
+<!-- LOCALIZATION NOTE (exampleCloseTag.label): DONT_TRANSLATE: they are text for HTML tagnames: "<i>" and "</i>" -->
+<!ENTITY exampleCloseTag.label "&lt;/i&gt;">
+<!ENTITY exampleText.label "Hello World!">
+<!ENTITY insertButton.label "Insert">
+<!ENTITY insertButton.accesskey "I">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EditorInsertTOC.dtd
@@ -0,0 +1,50 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is TOCMaker.
+   -
+   - The Initial Developer of the Original Code is
+   - Daniel Glazman.
+   - Portions created by the Initial Developer are Copyright (C) 2002
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -   Original author: Daniel Glazman (daniel@glazman.org)
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either the GNU General Public License Version 2 or later (the "GPL"), or
+   - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the LGPL or the GPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!ENTITY Window.title        "Table of Contents">
+<!ENTITY buildToc.label      "Build table of contents from:">
+<!ENTITY style.label         "Style:">
+<!ENTITY tag.label           "Tag:">
+<!ENTITY class.label         "Class:">
+<!ENTITY header1.label       "Level 1">
+<!ENTITY header2.label       "Level 2">
+<!ENTITY header3.label       "Level 3">
+<!ENTITY header4.label       "Level 4">
+<!ENTITY header5.label       "Level 5">
+<!ENTITY header6.label       "Level 6">
+<!ENTITY makeReadOnly.label  "Make the table of contents read-only">
+<!ENTITY orderedList.label   "Number all entries in the table of contents">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EditorInsertTable.dtd
@@ -0,0 +1,51 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-2000
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!-- Window title -->
+<!ENTITY windowTitle.label "Insert Table">
+
+<!ENTITY size.label "Size">
+<!ENTITY numRowsEditField.label "Rows:">
+<!ENTITY numRowsEditField.accessKey "R">
+<!ENTITY numColumnsEditField.label "Columns:">
+<!ENTITY numColumnsEditField.accessKey "C">
+<!ENTITY widthEditField.label "Width:">
+<!ENTITY widthEditField.accessKey "W">
+<!ENTITY borderEditField.label "Border:">
+<!ENTITY borderEditField.accessKey "B">
+<!ENTITY borderEditField.tooltip "Type a number for the table's border, or type zero (0) for no border">
+<!ENTITY pixels.label "pixels">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EditorLabelProperties.dtd
@@ -0,0 +1,50 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Button Properties Dialog.
+   -
+   - The Initial Developer of the Original Code is
+   - Neil Rashbrook.
+   - Portions created by the Initial Developer are Copyright (C) 2001
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s): Neil Rashbrook <neil@parkwaycc.co.uk>
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either the GNU General Public License Version 2 or later (the "GPL"), or
+   - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the LGPL or the GPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!ENTITY windowTitle.label "Label Properties">
+
+<!ENTITY Settings.label "Settings">
+<!ENTITY Settings.accesskey "S">
+
+<!ENTITY EditLabelText.label "Edit Text:">
+<!ENTITY EditLabelText.accesskey "T">
+<!ENTITY LabelFor.label "For Control:">
+<!ENTITY LabelFor.accesskey "F">
+<!ENTITY AccessKey.label "Access Key:">
+<!ENTITY AccessKey.accesskey "K">
+
+<!ENTITY RemoveLabel.label "Remove Label">
+<!ENTITY RemoveLabel.accesskey "R">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EditorLinkProperties.dtd
@@ -0,0 +1,39 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!ENTITY windowTitle.label "Link Properties">
+<!ENTITY LinkURLBox.label "Link Location">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EditorListProperties.dtd
@@ -0,0 +1,54 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+
+<!-- Window title -->
+<!ENTITY windowTitle.label "List Properties">
+
+<!ENTITY ListType.label "List Type">
+<!ENTITY bulletStyle.label "Bullet Style:">
+<!ENTITY startingNumber.label "Start at:">
+<!ENTITY startingNumber.accessKey "S">
+<!ENTITY none.value "None">
+<!ENTITY bulletList.value "Bullet (Unnumbered) List">
+<!ENTITY numberList.value "Numbered List">
+<!ENTITY definitionList.value "Definition List">
+<!ENTITY changeListMsg.label "When changing list type:">
+<!ENTITY changeEntireListRadio.label "Change entire list">
+<!ENTITY changeEntireListRadio.accessKey "C">
+<!ENTITY changeSelectedRadio.label "Change just selected items">
+<!ENTITY changeSelectedRadio.accessKey "I">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EditorPageProperties.dtd
@@ -0,0 +1,50 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!-- Window title -->
+<!ENTITY windowTitle.label "Page Properties">
+<!ENTITY location.label "Location:">
+<!ENTITY lastModified.label "Last Modified:">
+<!ENTITY titleInput.label "Title:">
+<!ENTITY titleInput.accessKey "T">
+<!ENTITY authorInput.label "Author:">
+<!ENTITY authorInput.accessKey "A">
+<!ENTITY descriptionInput.label "Description:">
+<!ENTITY descriptionInput.accessKey "D">
+<!ENTITY locationNewPage.label "[New page, not saved yet]">
+<!ENTITY EditHEADSource1.label "Advanced users:">
+<!ENTITY EditHEADSource2.label "To edit other contents of the &lt;head&gt; region, use &quot;HTML Source&quot; in the View Menu or Edit Mode Toolbar.">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EditorPersonalDictionary.dtd
@@ -0,0 +1,53 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!-- Window title -->
+<!ENTITY windowTitle.label "Personal Dictionary">
+
+<!ENTITY wordEditField.label "New word:">
+<!ENTITY wordEditField.accessKey "N">
+<!ENTITY AddButton.label "Add">
+<!ENTITY AddButton.accessKey "A">
+<!ENTITY DictionaryList.label "Words in dictionary:">
+<!ENTITY DictionaryList.accessKey "W">
+<!ENTITY ReplaceButton.label "Replace">
+<!ENTITY ReplaceButton.accessKey "R">
+<!ENTITY RemoveButton.label "Remove">
+<!ENTITY RemoveButton.accessKey "e">
+
+<!ENTITY CloseButton.label "Close">
+<!ENTITY CloseButton.accessKey "C">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EditorPublish.dtd
@@ -0,0 +1,103 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+
+<!-- Window title -->
+<!ENTITY windowTitle.label            "Publish Page">
+<!ENTITY windowTitleSettings.label    "Publish Settings">
+
+<!ENTITY publishTab.label             "Publish">
+<!ENTITY settingsTab.label            "Settings">
+
+<!ENTITY publishButton.label          "Publish">
+
+<!-- Publish Tab Panel -->
+<!ENTITY siteList.label               "Site Name:">
+<!ENTITY siteList.accesskey           "e">
+<!ENTITY siteList.tooltip             "Choose the site that you want to publish to">
+<!ENTITY newSiteButton.label          "New Site">
+<!ENTITY newSiteButton.accesskey      "N">
+<!ENTITY docDirList.label             "Site subdirectory for this page:">
+<!ENTITY docDirList.accesskey         "S">
+<!ENTITY docDirList.tooltip           "Choose or enter the name of the remote subdirectory for this page">
+<!ENTITY publishImgCheckbox.label     "Include images and other files">
+<!ENTITY publishImgCheckbox.accesskey "o">
+<!ENTITY publishImgCheckbox.tooltip   "Publish images and other files referenced by this page">
+<!ENTITY sameLocationRadio.label      "Use same location as page">
+<!ENTITY sameLocationRadio.accesskey  "U">
+<!ENTITY sameLocationRadio.tooltip    "Publish files to the same location as the page">
+<!ENTITY useSubdirRadio.label         "Use this site subdirectory:">
+<!ENTITY useSubdirRadio.accesskey     "d">
+<!ENTITY useSubdirRadio.tooltip       "Publish files to the selected remote subdirectory">
+<!ENTITY otherDirList.tooltip         "Choose or enter name of remote subdirectory where files will be published">
+<!ENTITY pageTitle.label              "Page Title:">
+<!ENTITY pageTitle.accesskey          "T">
+<!ENTITY pageTitle.tooltip            "Enter a title to identify the page in the window and in bookmarks">
+<!ENTITY pageTitleExample.label       "e.g.: &quot;My Web Page&quot;">
+<!ENTITY filename.label               "Filename:">
+<!ENTITY filename.accesskey           "F">
+<!ENTITY filename.tooltip             "Enter a name for this file, including '.html' for a web page">
+<!ENTITY filenameExample.label        "e.g,: &quot;mypage.html&quot;">
+<!ENTITY relatedDocs.label            "Other files to publish">
+<!ENTITY setDefaultButton.label       "Set as Default">
+<!ENTITY setDefaultButton.accesskey   "D">
+<!ENTITY setDefSiteAndDir.label       "Set as Default Site and Directory">
+<!ENTITY removeButton.label           "Remove Site">
+<!ENTITY removeButton.accesskey       "R">
+
+<!-- Settings Tab Panel -->
+<!ENTITY publishSites.label           "Publishing Sites">
+<!ENTITY serverInfo.label             "Server Information">
+<!ENTITY loginInfo.label              "Login Information">
+<!ENTITY siteName.label               "Site Name:">
+<!ENTITY siteName.accesskey           "e">
+<!ENTITY siteName.tooltip             "A nickname that identifies this publishing site (e.g.: 'MySite')">
+<!ENTITY siteUrl.label                "Publishing address (e.g.: 'ftp://ftp.myisp.com/myusername'):">
+<!ENTITY siteUrl.accesskey            "a">
+<!ENTITY siteUrl.tooltip              "The FTP:// or HTTP:// address provided by your ISP or web hosting service">
+<!ENTITY browseUrl.label              "HTTP address of your homepage (e.g.: 'http://www.myisp.com/myusername'):">
+<!ENTITY browseUrl.accesskey          "T">
+<!ENTITY browseUrl.tooltip            "The HTTP:// address of your home directory (don't include filename)">
+<!ENTITY username.label               "User name:">
+<!ENTITY username.accesskey           "U">
+<!ENTITY username.tooltip             "The user name you use to log in to your ISP or web hosting service">
+<!ENTITY password.label               "Password:">
+<!ENTITY password.accesskey           "w">
+<!ENTITY password.tooltip             "The password associated with your user name">
+<!ENTITY savePassword.label           "Save Password">
+<!ENTITY savePassword.accesskey       "S">
+<!ENTITY savePassword.tooltip         "Select this to save your password securely using Password Manager">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EditorPublishProgress.dtd
@@ -0,0 +1,52 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -   Charles Manske (cmanske@netscape.com)
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!-- Window title -->
+<!ENTITY siteUrl.label         "Site URL:">
+<!ENTITY docSubdir.label       "Page subdirectory:">
+<!ENTITY otherSubdir.label     "Image subdirectory:">
+
+<!ENTITY status.label          "Publishing…">
+<!ENTITY fileList.label        "Publishing Status">
+<!ENTITY statusHeader.label    "Status">
+<!ENTITY filenameHeader.label  "Filename">
+<!ENTITY succeeded.label       "Succeeded">
+<!ENTITY failed.label          "Failed">
+
+<!ENTITY keepOpen              "Keep this window open after publishing is complete.">
+<!ENTITY closeButton.label     "Close">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EditorReplace.dtd
@@ -0,0 +1,61 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -   Akkana Peck
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!-- extracted from EdReplace.xul -->
+
+<!ENTITY replaceDialog.title "Find and Replace">
+<!ENTITY findField.label "Find text:">
+<!ENTITY findField.accesskey "n">
+<!ENTITY replaceField.label "Replace with:">
+<!ENTITY replaceField.accesskey "e">
+<!ENTITY caseSensitiveCheckbox.label "Match exact case">
+<!ENTITY caseSensitiveCheckbox.accesskey "c">
+<!ENTITY wrapCheckbox.label "Wrap around">
+<!ENTITY wrapCheckbox.accesskey "W">
+<!ENTITY backwardsCheckbox.label "Search backwards">
+<!ENTITY backwardsCheckbox.accesskey "b">
+<!ENTITY findNextButton.label "Find Next">
+<!ENTITY findNextButton.accesskey "F">
+<!ENTITY replaceButton.label "Replace">
+<!ENTITY replaceButton.accesskey "R">
+<!ENTITY replaceAndFindButton.label "Replace and Find">
+<!ENTITY replaceAndFindButton.accesskey "d">
+<!ENTITY replaceAllButton.label "Replace All">
+<!ENTITY replaceAllButton.accesskey "A">
+<!ENTITY closeButton.label "Close">
+<!ENTITY notFoundWarning.label "The text you entered was not found.">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EditorSaveAsCharset.dtd
@@ -0,0 +1,50 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!-- These strings are generic to all or most of the editor's dialogs. -->
+
+<!-- This button is for the progressive disclosure of additional editing functionality -->
+
+<!-- These strings are for use specifically in the editor's link dialog. -->
+<!ENTITY windowTitle.label "Save And Change Character Encoding">
+<!ENTITY documentTitleTitle.label "Page Title">
+<!ENTITY documentCharsetTitle.label "Character Encoding">
+<!ENTITY documentCharsetDesc.label "Select the character encoding you want to save a document in:">
+<!ENTITY documentExportToText.label "Export to Text">
+
+
+
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EditorSelectProperties.dtd
@@ -0,0 +1,80 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Input Tag Properties Dialog.
+   -
+   - The Initial Developer of the Original Code is
+   - Neil Rashbrook.
+   - Portions created by the Initial Developer are Copyright (C) 2001
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s): Neil Rashbrook <neil@parkwaycc.co.uk>
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either the GNU General Public License Version 2 or later (the "GPL"), or
+   - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the LGPL or the GPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!ENTITY windowTitle.label "Selection List Properties">
+
+<!ENTITY Select.label "Selection List">
+<!ENTITY SelectName.label "List Name:">
+<!ENTITY SelectName.accesskey "N">
+<!ENTITY SelectSize.label "Height:">
+<!ENTITY SelectSize.accesskey "H">
+<!ENTITY SelectMultiple.label "Multiple Selection">
+<!ENTITY SelectMultiple.accesskey "M">
+<!ENTITY SelectDisabled.label "Disabled">
+<!ENTITY SelectDisabled.accesskey "D">
+<!ENTITY SelectTabIndex.label "Tab Index:">
+<!ENTITY SelectTabIndex.accesskey "I">
+
+<!ENTITY OptGroup.label "Option Group">
+<!ENTITY OptGroupLabel.label "Label:">
+<!ENTITY OptGroupLabel.accesskey "L">
+<!ENTITY OptGroupDisabled.label "Disabled">
+<!ENTITY OptGroupDisabled.accesskey "D">
+
+<!ENTITY Option.label "Option">
+<!ENTITY OptionText.label "Text:">
+<!ENTITY OptionText.accesskey "T">
+<!ENTITY OptionValue.label "Value:">
+<!ENTITY OptionValue.accesskey "V">
+<!ENTITY OptionSelected.label "Initially Selected">
+<!ENTITY OptionSelected.accesskey "S">
+<!ENTITY OptionDisabled.label "Disabled">
+<!ENTITY OptionDisabled.accesskey "D">
+
+<!ENTITY TextHeader.label "Text">
+<!ENTITY ValueHeader.label "Value">
+<!ENTITY SelectedHeader.label "Selected">
+
+<!ENTITY AddOption.label "Add Option">
+<!ENTITY AddOption.accesskey "O">
+<!ENTITY AddOptGroup.label "Add Group">
+<!ENTITY AddOptGroup.accesskey "G">
+<!ENTITY RemoveElement.label "Remove">
+<!ENTITY RemoveElement.accesskey "R">
+<!ENTITY MoveElementUp.label "Move Up">
+<!ENTITY MoveElementUp.accesskey "U">
+<!ENTITY MoveElementDown.label "Move Down">
+<!ENTITY MoveElementDown.accesskey "D">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EditorSnapToGrid.dtd
@@ -0,0 +1,48 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla.org.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 2003
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -   Daniel Glazman (glazman@netscape.com) (Original author)
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either the GNU General Public License Version 2 or later (the "GPL"), or
+   - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the LGPL or the GPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+
+<!-- Window title -->
+<!ENTITY windowTitle.label "Snap to Grid">
+
+<!ENTITY enableSnapToGrid.label "enable Snap to Grid">
+<!ENTITY enableSnapToGrid.accessKey "e">
+
+<!ENTITY sizeEditField.label "Size:">
+<!ENTITY sizeEditField.accessKey "S">
+
+<!ENTITY pixelsLabel.value "pixels">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EditorSpellCheck.dtd
@@ -0,0 +1,71 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!-- Window title -->
+<!ENTITY windowTitle.label "Check Spelling">
+
+<!ENTITY misspelledWord.label "Misspelled word:">
+<!ENTITY wordEditField.label "Replace with:">
+<!ENTITY wordEditField.accessKey "w">
+<!ENTITY checkwordButton.label "Check Word">
+<!ENTITY checkwordButton.accessKey "k">
+<!ENTITY suggestions.label "Suggestions:">
+<!ENTITY suggestions.accessKey "u">
+<!ENTITY ignoreButton.label "Ignore">
+<!ENTITY ignoreButton.accessKey "I">
+<!ENTITY ignoreAllButton.label "Ignore All">
+<!ENTITY ignoreAllButton.accessKey "n">
+<!ENTITY replaceButton.label "Replace">
+<!ENTITY replaceButton.accessKey "R">
+<!ENTITY replaceAllButton.label "Replace All">
+<!ENTITY replaceAllButton.accessKey "A">
+<!ENTITY stopButton.label "Stop">
+<!ENTITY stopButton.accessKey "t">
+<!ENTITY userDictionary.label "Personal Dictionary:">
+<!ENTITY moreDictionaries.label "Download more dictionaries…">
+<!ENTITY addToUserDictionaryButton.label "Add Word">
+<!ENTITY addToUserDictionaryButton.accessKey "d">
+<!ENTITY editUserDictionaryButton.label "Edit…">
+<!ENTITY editUserDictionaryButton.accessKey "E">
+<!ENTITY recheckButton.label "Recheck Page">
+<!ENTITY recheckButton.accessKey "P">
+<!ENTITY closeButton.label "Close">
+<!ENTITY closeButton.accessKey "C">
+<!ENTITY sendButton.label "Send">
+<!ENTITY sendButton.accessKey "S">
+<!ENTITY languagePopup.label "Language:">
+<!ENTITY languagePopup.accessKey "L">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EditorTableProperties.dtd
@@ -0,0 +1,116 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Mozilla Communicator client code, released
+   - March 31, 1998.
+   -
+   - The Initial Developer of the Original Code is
+   - Netscape Communications Corporation.
+   - Portions created by the Initial Developer are Copyright (C) 1998-1999
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s):
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either of the GNU General Public License Version 2 or later (the "GPL"),
+   - or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the GPL or the LGPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!ENTITY tableWindow.title                "Table Properties">
+<!ENTITY applyButton.label                "Apply">
+<!ENTITY applyButton.accesskey            "A">
+<!ENTITY closeButton.label                "Close">
+<!ENTITY tableTab.label                   "Table">
+<!ENTITY cellTab.label                    "Cells">
+<!ENTITY tableRows.label                  "Rows:">
+<!ENTITY tableRows.accessKey              "R">
+<!ENTITY tableColumns.label               "Columns:">
+<!ENTITY tableColumns.accessKey           "C">
+<!ENTITY tableHeight.label                "Height:">
+<!ENTITY tableHeight.accessKey            "G">
+<!ENTITY tableWidth.label                 "Width:">
+<!ENTITY tableWidth.accessKey             "W">
+<!ENTITY tableBorderSpacing.label         "Borders and Spacing">
+<!ENTITY tableBorderWidth.label           "Border:">
+<!ENTITY tableBorderWidth.accessKey       "B">
+<!ENTITY tableSpacing.label               "Spacing:">
+<!ENTITY tableSpacing.accessKey           "S">
+<!ENTITY tablePadding.label               "Padding:">
+<!ENTITY tablePadding.accessKey           "P">
+<!ENTITY tablePxBetwCells.label           "pixels between cells">
+<!ENTITY tablePxBetwBrdrCellContent.label "pixels between cell border and content">
+<!ENTITY tableAlignment.label             "Table Alignment:">
+<!ENTITY tableAlignment.accessKey         "T">
+<!ENTITY tableCaption.label               "Caption:">
+<!ENTITY tableCaption.accessKey           "N">
+<!ENTITY tableCaptionAbove.label          "Above Table">
+<!ENTITY tableCaptionBelow.label          "Below Table">
+<!ENTITY tableCaptionLeft.label           "Left of Table">
+<!ENTITY tableCaptionRight.label          "Right of table">
+<!ENTITY tableCaptionNone.label           "None">
+<!ENTITY tableInheritColor.label           "(Let page color show through)">
+
+<!ENTITY cellPercent.label                "percent of table">
+<!ENTITY cellSelection.label              "Selection">
+<!ENTITY cellSelectCell.label             "Cell">
+<!ENTITY cellSelectRow.label              "Row">
+<!ENTITY cellSelectColumn.label           "Column">
+<!ENTITY cellSelectNext.label             "Next">
+<!ENTITY cellSelectNext.accessKey         "N">
+<!ENTITY cellSelectPrevious.label         "Previous">
+<!ENTITY cellSelectPrevious.accessKey     "P">
+<!ENTITY cellApplyBeforeMove.label        "Apply changes before changing selection">
+<!ENTITY cellKeepCurrentData.label        "Keep current settings">
+<!-- LOCALIZATION NOTE Next 2 form 1 sentence (we don't want to use HTML tag to wrap) -->
+<!ENTITY applyBeforeChange1.label         "Current changes will be applied">
+<!ENTITY applyBeforeChange2.label         "before changing the selection.">
+<!ENTITY cellRowSpan.label                "Row Span:">
+<!ENTITY cellColSpan.label                "Column Span:">
+<!ENTITY cellContentAlignment.label       "Content Alignment">
+<!ENTITY cellHorizontal.label             "Horizontal:">
+<!ENTITY cellHorizontal.accessKey         "Z">
+<!ENTITY cellVertical.label               "Vertical:">
+<!ENTITY cellVertical.accessKey           "V">
+<!ENTITY cellStyle.label                  "Cell Style:">
+<!ENTITY cellStyle.accessKey              "C">
+<!ENTITY cellNormal.label                 "Normal">
+<!ENTITY cellHeader.label                 "Header">
+<!ENTITY cellTextWrap.label               "Text Wrap:">
+<!ENTITY cellTextWrap.accessKey           "T">
+<!ENTITY cellWrap.label                   "Wrap">
+<!ENTITY cellNoWrap.label                 "Don't wrap">
+<!ENTITY cellAlignTop.label               "Top">
+<!ENTITY cellAlignMiddle.label            "Middle">
+<!ENTITY cellAlignBottom.label            "Bottom">
+<!ENTITY cellAlignJustify.label           "Justify">
+<!ENTITY cellAlignAtChar.label            "At Character:">
+<!ENTITY cellInheritColor.label           "(Let table color show through)">
+<!ENTITY cellUseCheckboxHelp.label        "Use checkboxes to determine which properties are applied to all selected cells">
+
+<!-- Used in both Table and Cell panels  -->
+<!ENTITY size.label                       "Size">
+<!ENTITY pixels.label                     "pixels">
+<!ENTITY backgroundColor.label            "Background Color:">
+<!ENTITY backgroundColor.accessKey        "B">
+<!ENTITY AlignLeft.label                  "Left">
+<!ENTITY AlignCenter.label                "Center">
+<!ENTITY AlignRight.label                 "Right">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/dialogs/EditorTextAreaProperties.dtd
@@ -0,0 +1,65 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+   - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   -
+   - The contents of this file are subject to the Mozilla Public License Version
+   - 1.1 (the "License"); you may not use this file except in compliance with
+   - the License. You may obtain a copy of the License at
+   - http://www.mozilla.org/MPL/
+   -
+   - Software distributed under the License is distributed on an "AS IS" basis,
+   - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   - for the specific language governing rights and limitations under the
+   - License.
+   -
+   - The Original Code is Text Area Properties Dialog.
+   -
+   - The Initial Developer of the Original Code is
+   - Neil Rashbrook.
+   - Portions created by the Initial Developer are Copyright (C) 2001
+   - the Initial Developer. All Rights Reserved.
+   -
+   - Contributor(s): Neil Rashbrook <neil@parkwaycc.co.uk>
+   -
+   - Alternatively, the contents of this file may be used under the terms of
+   - either the GNU General Public License Version 2 or later (the "GPL"), or
+   - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   - in which case the provisions of the GPL or the LGPL are applicable instead
+   - of those above. If you wish to allow use of your version of this file only
+   - under the terms of either the GPL or the LGPL, and not to allow others to
+   - use your version of this file under the terms of the MPL, indicate your
+   - decision by deleting the provisions above and replace them with the notice
+   - and other provisions required by the LGPL or the GPL. If you do not delete
+   - the provisions above, a recipient may use your version of this file under
+   - the terms of any one of the MPL, the GPL or the LGPL.
+   -
+   - ***** END LICENSE BLOCK ***** -->
+
+<!ENTITY windowTitle.label "Text Area Properties">
+
+<!ENTITY Settings.label "Settings">
+
+<!ENTITY TextAreaName.label "Field Name:">
+<!ENTITY TextAreaName.accessKey "N">
+<!ENTITY TextAreaRows.label "Rows:">
+<!ENTITY TextAreaRows.accessKey "R">
+<!ENTITY TextAreaCols.label "Columns:">
+<!ENTITY TextAreaCols.accessKey "C">
+<!ENTITY TextAreaReadOnly.label "Read Only">
+<!ENTITY TextAreaReadOnly.accessKey "O">
+<!ENTITY TextAreaDisabled.label "Disabled">
+<!ENTITY TextAreaDisabled.accessKey "D">
+<!ENTITY TextAreaTabIndex.label "Tab Index:">
+<!ENTITY TextAreaTabIndex.accessKey "I">
+<!ENTITY TextAreaAccessKey.label "Access Key:">
+<!ENTITY TextAreaAccessKey.accessKey "K">
+<!ENTITY InitialText.label "Initial Text:">
+<!ENTITY InitialText.accessKey "T">
+
+<!ENTITY TextAreaWrap.label "Wrap Mode:">
+<!ENTITY TextAreaWrap.accessKey "W">
+<!ENTITY WrapDefault.value "Default">
+<!ENTITY WrapOff.value "Off">
+<!ENTITY WrapHard.value "Hard">
+<!ENTITY WrapSoft.value "Soft">
+<!ENTITY WrapPhysical.value "Physical">
+<!ENTITY WrapVirtual.value "Virtual">
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/en-US/chrome/region/region.properties
@@ -0,0 +1,4 @@
+#
+# editor.js
+# editor.properties
+editor.throbber.url=http://www.seamonkey-project.org/
new file mode 100644
--- /dev/null
+++ b/editor/ui/locales/jar.mn
@@ -0,0 +1,54 @@
+#filter substitution
+
+@AB_CD@.jar:
+% locale editor @AB_CD@ %locale/@AB_CD@/editor/
+  locale/@AB_CD@/editor/editorSmileyOverlay.dtd              (%chrome/composer/editorSmileyOverlay.dtd)
+  locale/@AB_CD@/editor/editorOverlay.dtd                    (%chrome/composer/editorOverlay.dtd)
+  locale/@AB_CD@/editor/editor.properties                    (%chrome/composer/editor.properties)
+  locale/@AB_CD@/editor/EditorHLineProperties.dtd            (%chrome/dialogs/EditorHLineProperties.dtd)
+  locale/@AB_CD@/editor/EditorImageProperties.dtd            (%chrome/dialogs/EditorImageProperties.dtd)
+  locale/@AB_CD@/editor/EditorInsertSource.dtd               (%chrome/dialogs/EditorInsertSource.dtd)
+  locale/@AB_CD@/editor/EditorInsertChars.dtd                (%chrome/dialogs/EditorInsertChars.dtd)
+  locale/@AB_CD@/editor/EditorInsertTable.dtd                (%chrome/dialogs/EditorInsertTable.dtd)
+  locale/@AB_CD@/editor/EditorInsertTOC.dtd                  (%chrome/dialogs/EditorInsertTOC.dtd)
+  locale/@AB_CD@/editor/EditorLinkProperties.dtd             (%chrome/dialogs/EditorLinkProperties.dtd)
+  locale/@AB_CD@/editor/EditorListProperties.dtd             (%chrome/dialogs/EditorListProperties.dtd)
+  locale/@AB_CD@/editor/EditorColorProperties.dtd            (%chrome/dialogs/EditorColorProperties.dtd)
+  locale/@AB_CD@/editor/EdColorPicker.dtd                    (%chrome/dialogs/EdColorPicker.dtd)
+  locale/@AB_CD@/editor/EditorReplace.dtd                    (%chrome/dialogs/EditorReplace.dtd)
+  locale/@AB_CD@/editor/EditorSpellCheck.dtd                 (%chrome/dialogs/EditorSpellCheck.dtd)
+  locale/@AB_CD@/editor/EditorPersonalDictionary.dtd         (%chrome/dialogs/EditorPersonalDictionary.dtd)
+  locale/@AB_CD@/editor/EditorTableProperties.dtd            (%chrome/dialogs/EditorTableProperties.dtd)
+  locale/@AB_CD@/editor/EditorFormProperties.dtd             (%chrome/dialogs/EditorFormProperties.dtd)
+  locale/@AB_CD@/editor/EditorInputProperties.dtd            (%chrome/dialogs/EditorInputProperties.dtd)
+  locale/@AB_CD@/editor/EditorTextAreaProperties.dtd         (%chrome/dialogs/EditorTextAreaProperties.dtd)
+  locale/@AB_CD@/editor/EditorSelectProperties.dtd           (%chrome/dialogs/EditorSelectProperties.dtd)
+  locale/@AB_CD@/editor/EditorButtonProperties.dtd           (%chrome/dialogs/EditorButtonProperties.dtd)
+  locale/@AB_CD@/editor/EditorLabelProperties.dtd            (%chrome/dialogs/EditorLabelProperties.dtd)
+  locale/@AB_CD@/editor/EditorFieldSetProperties.dtd         (%chrome/dialogs/EditorFieldSetProperties.dtd)
+  locale/@AB_CD@/editor/EdNamedAnchorProperties.dtd          (%chrome/dialogs/EdNamedAnchorProperties.dtd)
+  locale/@AB_CD@/editor/EdDialogOverlay.dtd                  (%chrome/dialogs/EdDialogOverlay.dtd)
+  locale/@AB_CD@/editor/EdAdvancedEdit.dtd                   (%chrome/dialogs/EdAdvancedEdit.dtd)
+  locale/@AB_CD@/editor/EdConvertToTable.dtd                 (%chrome/dialogs/EdConvertToTable.dtd)
+
+
+#ifdef MOZ_SUITE
+@AB_CD@.jar:
+% locale editor-region @AB_CD@ %locale/@AB_CD@/editor-region/
+  locale/@AB_CD@/editor/editor.dtd                           (%chrome/composer/editor.dtd)
+  locale/@AB_CD@/editor/editorPrefsOverlay.dtd               (%chrome/composer/editorPrefsOverlay.dtd)
+  locale/@AB_CD@/editor/editorNavigatorOverlay.dtd           (%chrome/composer/editorNavigatorOverlay.dtd)
+  locale/@AB_CD@/editor/pref-toolbars.dtd                    (%chrome/composer/pref-toolbars.dtd)
+  locale/@AB_CD@/editor/pref-editing.dtd                     (%chrome/composer/pref-editing.dtd)
+  locale/@AB_CD@/editor/pref-composer.dtd                    (%chrome/composer/pref-composer.dtd)
+  locale/@AB_CD@/editor/EdLinkChecker.dtd                    (%chrome/dialogs/EdLinkChecker.dtd)
+  locale/@AB_CD@/editor/EditorPageProperties.dtd             (%chrome/dialogs/EditorPageProperties.dtd)
+  locale/@AB_CD@/editor/EditorSnapToGrid.dtd                 (%chrome/dialogs/EditorSnapToGrid.dtd)
+  locale/@AB_CD@/editor/EditorImageMap.dtd                   (%chrome/dialogs/EditorImageMap.dtd)
+  locale/@AB_CD@/editor/EditorImageMapHotSpot.dtd            (%chrome/dialogs/EditorImageMapHotSpot.dtd)
+  locale/@AB_CD@/editor/EditConflict.dtd                     (%chrome/dialogs/EditConflict.dtd)
+  locale/@AB_CD@/editor/EditorSaveAsCharset.dtd              (%chrome/dialogs/EditorSaveAsCharset.dtd)
+  locale/@AB_CD@/editor/EditorPublish.dtd                    (%chrome/dialogs/EditorPublish.dtd)
+  locale/@AB_CD@/editor/EditorPublishProgress.dtd            (%chrome/dialogs/EditorPublishProgress.dtd)
+  locale/@AB_CD@/editor-region/region.properties             (%chrome/region/region.properties)
+#endif
new file mode 100644
--- /dev/null
+++ b/editor/ui/makefiles.sh
@@ -0,0 +1,42 @@
+#! /bin/sh
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is the the Mozilla build system
+#
+# The Initial Developer of the Original Code is
+# Ben Turner <mozilla@songbirdnest.com>
+#
+# Portions created by the Initial Developer are Copyright (C) 2007
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+add_makefiles "
+editor/ui/Makefile
+editor/ui/locales/Makefile
+"
new file mode 100644
--- /dev/null
+++ b/editor/ui/nsComposerCmdLineHandler.js
@@ -0,0 +1,215 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Seamonkey Composer.
+ *
+ * The Initial Developer of the Original Code is
+ * Benjamin Smedberg <bsmedberg@covad.net>.
+ * Portions created by the Initial Developer are Copyright (C) 2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+const nsICmdLineHandler     = Components.interfaces.nsICmdLineHandler;
+const nsICommandLineHandler = Components.interfaces.nsICommandLineHandler;
+const nsIFactory            = Components.interfaces.nsIFactory;
+const nsISupports           = Components.interfaces.nsISupports;
+const nsIModule             = Components.interfaces.nsIModule;
+const nsIComponentRegistrar = Components.interfaces.nsIComponentRegistrar;
+const nsICategoryManager    = Components.interfaces.nsICategoryManager;
+const nsISupportsString     = Components.interfaces.nsISupportsString;
+const nsIWindowWatcher      = Components.interfaces.nsIWindowWatcher;
+
+const NS_ERROR_FAILURE        = Components.results.NS_ERROR_FAILURE;
+const NS_ERROR_NO_AGGREGATION = Components.results.NS_ERROR_NO_AGGREGATION;
+const NS_ERROR_NO_INTERFACE   = Components.results.NS_ERROR_NO_INTERFACE;
+
+function nsComposerCmdLineHandler() {}
+nsComposerCmdLineHandler.prototype = {
+  get wrappedJSObject() {
+    return this;
+  },
+
+  /* nsISupports */
+
+  QueryInterface: function(iid) {
+    if (iid.equals(nsISupports))
+      return this;
+
+    if (nsICmdLineHandler && iid.equals(nsICmdLineHandler))
+      return this;
+
+    if (nsICommandLineHandler && iid.equals(nsICommandLineHandler))
+      return this;
+
+    throw NS_ERROR_NO_INTERFACE;
+  },
+
+  /* nsICmdLineHandler */
+  commandLineArgument : "-edit",
+  prefNameForStartup : "general.startup.editor",
+  chromeUrlForTask : "chrome://editor/content/editor.xul",
+  helpText : "Start with editor.",
+  handlesArgs : true,
+  defaultArgs : "about:blank",
+  openWindowWithArgs : true,
+
+  /* nsICommandLineHandler */
+  handle : function handle(cmdLine) {
+    var args = Components.classes["@mozilla.org/supports-string;1"]
+                         .createInstance(nsISupportsString);
+    try {
+      var uristr = cmdLine.handleFlagWithParam("edit", false);
+      if (uristr == null) {
+        // Try the editor flag (used for general.startup.* prefs)
+        uristr = cmdLine.handleFlagWithParam("editor", false);
+        if (uristr == null)
+          return;
+      }
+
+      try {
+        args.data = cmdLine.resolveURI(uristr).spec;
+      }
+      catch (e) {
+        return;
+      }
+    }
+    catch (e) {
+      // One of the flags is present but no data, so set default arg.
+      args.data = "about:blank";
+    }
+
+    var wwatch = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
+                           .getService(nsIWindowWatcher);
+    wwatch.openWindow(null, "chrome://editor/content", "_blank",
+                      "chrome,dialog=no,all", args);
+    cmdLine.preventDefault = true;
+  },
+
+  helpInfo : "  -edit <url>          Open Composer.\n"
+};
+
+function nsComposerCmdLineHandlerFactory() {
+}
+
+nsComposerCmdLineHandlerFactory.prototype = {
+  /* nsISupports */
+
+  QueryInterface: function(iid) {
+    if (!iid.equals(nsIFactory) &&
+        !iid.equals(nsISupports)) {
+          throw Components.results.NS_ERROR_NO_INTERFACE;
+    }
+    return this;
+  },
+
+  /* nsIFactory */
+  createInstance: function(outer, iid) {
+    if (outer != null) {
+      throw NS_ERROR_NO_AGGREGATION;
+    }
+
+    return new nsComposerCmdLineHandler().QueryInterface(iid);
+  },
+
+  lockFactory: function(lock) {
+  }
+};
+
+const nsComposerCmdLineHandler_CID =
+  Components.ID("{f7d8db95-ab5d-4393-a796-9112fe758cfa}");
+
+const ContractIDPrefix =
+  "@mozilla.org/commandlinehandler/general-startup;1?type=";
+
+var thisModule = {
+  /* nsISupports */
+
+  QueryInterface: function(iid) {
+    if (!iid.equals(nsIModule) &&
+        !iid.equals(nsISupports)) {
+          throw Components.results.NS_ERROR_NO_INTERFACE;
+    }
+    return this;
+  },
+
+  /* nsIModule */
+
+  getClassObject: function (compMgr, cid, iid) {
+    if (!cid.equals(nsComposerCmdLineHandler_CID)) {
+      throw NS_ERROR_FAILURE;
+    }
+
+    if (!iid.equals(nsIFactory)) {
+      throw NS_ERROR_NO_INTERFACE;
+    }
+
+    return new nsComposerCmdLineHandlerFactory();
+  },
+
+  registerSelf: function (compMgr, fileSpec, location, type) {
+    var compReg = compMgr.QueryInterface(nsIComponentRegistrar);
+    compReg.registerFactoryLocation(nsComposerCmdLineHandler_CID,
+                                    "nsComposerCmdLineHandler",
+                                    ContractIDPrefix + "edit",
+                                    fileSpec, location, type);
+    compReg.registerFactoryLocation(nsComposerCmdLineHandler_CID,
+                                    "nsComposerCmdLineHandler",
+                                    ContractIDPrefix + "editor",
+                                    fileSpec, location, type);
+
+    var catMan = Components.classes["@mozilla.org/categorymanager;1"].getService(nsICategoryManager);
+    catMan.addCategoryEntry("command-line-argument-handlers",
+                            "nsComposerCmdLineHandler",
+                            ContractIDPrefix + "edit",
+                            true, true);
+    catMan.addCategoryEntry("command-line-handler",
+                            "m-edit",
+                            ContractIDPrefix + "edit",
+                            true, true);
+  },
+
+  unregisterSelf: function (compMgr, location, type) {
+    var compReg = compMgr.QueryInterface(nsIComponentRegistrar);
+    compReg.unregisterFactoryLocation(nsComposerCmdLineHandler_CID,
+                                      location);
+
+    var catMan = Components.classes["@mozilla.org/categorymanager;1"].getService(nsICategoryManager);
+    catMan.deleteCategoryEntry("command-line-argument-handlers",
+                               "nsComposerCmdLineHandler", true);
+    catMan.deleteCategoryEntry("command-line-handler",
+                               "m-edit", true);
+  },    
+
+  canUnload: function (compMgr) {
+    return true;
+  }
+};
+
+function NSGetModule(compMgr, fileSpec) {
+  return thisModule;
+}
--- a/mail/build.mk
+++ b/mail/build.mk
@@ -38,31 +38,33 @@
 ifndef COMM_BUILD # Mozilla Makefile
 
 ifndef LIBXUL_SDK
 include $(topsrcdir)/toolkit/toolkit-tiers.mk
 endif
 
 TIERS += app
 
-tier_app_dirs += editor/ui
-
 ifdef MOZ_EXTENSIONS
 tier_app_dirs += extensions
 endif
 
 else # toplevel Makefile
 
 TIERS += app
 
 ifdef MOZ_LDAP_XPCOM
 tier_app_staticdirs += directory/c-sdk
 tier_app_dirs += directory/xpcom
 endif
 
+ifdef MOZ_COMPOSER
+tier_app_dirs += editor/ui
+endif
+
 ifdef MOZ_BRANDING_DIRECTORY
 tier_app_dirs += $(MOZ_BRANDING_DIRECTORY)
 else
 tier_app_dirs += mail/branding/nightly
 endif
 
 tier_app_dirs += \
 	mailnews \
--- a/mail/locales/Makefile.in
+++ b/mail/locales/Makefile.in
@@ -106,17 +106,17 @@ ISP_FILES = $(shell cat $(LOCALE_SRCDIR)
 libs:: $(addsuffix .rdf,$(ISP_FILES)) 
 	$(SYSINSTALL) $(IFLAGS1) $^ $(FINAL_TARGET)/isp/$(AB_CD)
 
 install:: $(addsuffix .rdf,$(ISP_FILES))
 	$(SYSINSTALL) $(IFLAGS1) $^ $(DESTDIR)$(mozappdir)/isp/$(AB_CD)
 
 libs-%:
 	@$(MAKE) -C ../../mozilla/toolkit/locales libs-$*
-	@$(MAKE) -C ../../mozilla/editor/ui/locales AB_CD=$* XPI_NAME=locale-$*
+	@$(MAKE) -C ../../editor/ui/locales AB_CD=$* XPI_NAME=locale-$*
 	@$(MAKE) -C ../../mozilla/extensions/spellcheck/locales AB_CD=$* XPI_NAME=locale-$*
 	@$(MAKE) libs AB_CD=$* XPI_NAME=locale-$* PREF_DIR=defaults/pref
 ifdef MOZ_BRANDING_DIRECTORY
 	@$(MAKE) -C $(DEPTH)/$(MOZ_BRANDING_DIRECTORY)/locales AB_CD=$* XPI_NAME=locale-$*
 else
 	@$(MAKE) -C $(DEPTH)/mail/branding/nightly/locales AB_CD=$* XPI_NAME=locale-$*
 endif
 
--- a/suite/build.mk
+++ b/suite/build.mk
@@ -38,33 +38,33 @@
 ifndef COMM_BUILD # Mozilla Makefile
 
 ifndef LIBXUL_SDK
 include $(topsrcdir)/toolkit/toolkit-tiers.mk
 endif
 
 TIERS += app
 
-ifdef MOZ_COMPOSER
-tier_app_dirs += editor/ui
-endif
-
 ifdef MOZ_EXTENSIONS
 tier_app_dirs += extensions
 endif
 
 else # toplevel Makefile
 
 TIERS += app
 
 ifdef MOZ_LDAP_XPCOM
 tier_app_staticdirs += directory/c-sdk
 tier_app_dirs += directory/xpcom
 endif
 
+ifdef MOZ_COMPOSER
+tier_app_dirs += editor/ui
+endif
+
 ifdef MOZ_BRANDING_DIRECTORY
 tier_app_dirs += $(MOZ_BRANDING_DIRECTORY)
 endif
 
 ifdef MOZ_MAIL_NEWS
 tier_app_dirs += mailnews
 endif
 
--- a/suite/locales/Makefile.in
+++ b/suite/locales/Makefile.in
@@ -133,17 +133,17 @@ SEARCH_PLUGINS := $(shell cat $(LOCALE_S
 libs:: $(addsuffix .src,$(SEARCH_PLUGINS)) $(addsuffix .png,$(SEARCH_PLUGINS))
 	$(SYSINSTALL) $(IFLAGS1) $^ $(FINAL_TARGET)/searchplugins
 
 install:: $(addsuffix .src,$(SEARCH_PLUGINS)) $(addsuffix .png,$(SEARCH_PLUGINS))
 	$(SYSINSTALL) $(IFLAGS1) $^ $(DESTDIR)$(mozappdir)/searchplugins
 
 libs-%:
 	@$(MAKE) -C ../../mozilla/toolkit/locales libs-$*
-	@$(MAKE) -C ../../mozilla/editor/ui/locales AB_CD=$* XPI_NAME=locale-$*
+	@$(MAKE) -C ../../editor/ui/locales AB_CD=$* XPI_NAME=locale-$*
 	@$(MAKE) -C ../../mozilla/extensions/irc/locales libs-$*
 	@$(MAKE) -C ../../mozilla/extensions/venkman/locales libs-$*
 	@$(MAKE) -C ../../mozilla/extensions/reporter/locales libs AB_CD=$* XPI_NAME=locale-$*
 	@$(MAKE) -C ../../mozilla/extensions/spellcheck/locales AB_CD=$* XPI_NAME=locale-$*
 	@$(MAKE) libs AB_CD=$* XPI_NAME=locale-$* PREF_DIR=defaults/pref
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
 MOZ_PKG_MAC_DSSTORE=$(_ABS_DIST)/branding/dsstore